我在Mac OS X 10.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"
是IPv4
的{{1}}地址。
"www.google.com"
输出为//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"
的服务端口很奇怪。
有人可以解释一下吗?
答案 0 :(得分:3)
这是一个影响iOS 9和Mac OS X 10.11的错误。它已在iOS 10和macOS 10.12中修复,但这里有解决方法,可用于支持运行iOS 9和Mac OS X 10.11的设备:
如果您使用的是已知或注册的端口号,则可以将服务名称而不是端口号作为字符串传递。在此示例中,只需将"80"
替换为"http"
:
if (getaddrinfo("216.58.199.4", "http", &hints, &res)) {
由于错误仅限于数字解析,因此使用服务名称仍然有效。可以在/etc/services
中找到已知服务的完整列表。
如果您不使用/etc/services
中的端口号,则可以手动将正确的端口号写入struct 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));
}
}