我在MacOSX10.11.2中测试IPv6,发现了一个奇怪的问题。
我使用getaddrinfo将主机名解析为IPv6地址:
#include <stdio.h>
#include <netdb.h>
#include <errno.h>
#include <string.h>
#include <arpa/inet.h>
int main(int argc, const char * argv[]) {
struct addrinfo * res, * addr;
struct addrinfo hints;
char buffer[128];
struct sockaddr_in6 * sockaddr_v6;
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_DEFAULT;
if (getaddrinfo("www.google.com", "80", &hints, &res)) {
//if (getaddrinfo("216.58.199.4", "80", &hints, &res)) {
printf("getaddrinfo failed with errno(-%d)\n", errno);
return 0;
}
for (addr = res;addr;addr = addr->ai_next)
{
if (addr->ai_family == AF_INET6)
{
sockaddr_v6 = (struct sockaddr_in6 *)addr->ai_addr;
printf("ipv6 addr is %s %d)\n", inet_ntop(AF_INET6, &sockaddr_v6->sin6_addr, buffer, sizeof(buffer)), ntohs(sockaddr_v6->sin6_port));
}
}
freeaddrinfo(res);
return 0;
}
输出为
"ipv6 addr is 64:ff9b::d83a:c704 80". everything is ok !
"www.google.com" is resolved to "64:ff9b::d83a:c704", sin6_port is 80.
但是当我使用"216.58.199.4"
而不是"www.google.com"
时,"216.58.199.4"
是"www.google.com"
的IPv4
地址。
//if (getaddrinfo("www.google.com", "80", &hints, &res)) {
if (getaddrinfo("216.58.199.4", "80", &hints, &res)) {
输出为"ipv6 addr is 64:ff9b::d83a:c704 0"
。可以将"216.58.199.4"
转换为"64:ff9b::d83a:c704"
,但奇怪的是80 become 0
的服务端口。
有谁能解释一下吗?
发布于 2016-05-24 00:40:48
这是一个影响iOS 9和MacOSX10.11的错误。该问题已在iOS 10和macOS 10.12中修复,但以下是可用于支持运行iOS 9和macOS 10.11的设备的变通方法:
解决方法1:使用服务名称
如果您使用的是众所周知的或已注册的端口号,则可以将服务名作为字符串传递,而不是端口号。在本例中,只需将"80"
替换为"http"
if (getaddrinfo("216.58.199.4", "http", &hints, &res)) {
由于该错误仅限于数字解析,因此使用服务名称仍然有效。已知服务的完整列表可在/etc/services
中找到。
解决方法2:手动将端口写入sockaddr
如果您不使用来自/etc/services
的端口号,您可以手动将正确的端口号写入您的struct sockaddr
。如果这样做,重要的是:
sockaddr使用网络字节顺序,因此您需要使用htons()
来转换您的端口号。
以下是应用于您的示例的解决方法:
for (addr = res;addr;addr = addr->ai_next)
{
if (addr->ai_family == AF_INET6)
{
sockaddr_v6 = (struct sockaddr_in6 *)addr->ai_addr;
// START WORKAROUND
if (sockaddr_v6->sin6_port == 0)
{
sockaddr_v6->sin6_port = htons(80);
}
// END WORKAROUND
printf("ipv6 addr is %s %d)\n", inet_ntop(AF_INET6, &sockaddr_v6->sin6_addr, buffer, sizeof(buffer)), ntohs(sockaddr_v6->sin6_port));
}
}
https://stackoverflow.com/questions/37386161
复制相似问题