首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用getaddrinfo将IPv4地址转换为IPv6地址时,缺少服务端口

使用getaddrinfo将IPv4地址转换为IPv6地址时,缺少服务端口
EN

Stack Overflow用户
提问于 2016-05-23 16:30:20
回答 1查看 619关注 0票数 2

我在MacOSX10.11.2中测试IPv6,发现了一个奇怪的问题。

我使用getaddrinfo将主机名解析为IPv6地址:

代码语言:javascript
运行
复制
#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;
}

输出为

代码语言:javascript
运行
复制
"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地址。

代码语言:javascript
运行
复制
//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的服务端口。

有谁能解释一下吗?

EN

回答 1

Stack Overflow用户

发布于 2016-05-24 00:40:48

这是一个影响iOS 9和MacOSX10.11的错误。该问题已在iOS 10和macOS 10.12中修复,但以下是可用于支持运行iOS 9和macOS 10.11的设备的变通方法:

解决方法1:使用服务名称

如果您使用的是众所周知的或已注册的端口号,则可以将服务名作为字符串传递,而不是端口号。在本例中,只需将"80"替换为"http"

代码语言:javascript
运行
复制
if (getaddrinfo("216.58.199.4", "http", &hints, &res)) {

由于该错误仅限于数字解析,因此使用服务名称仍然有效。已知服务的完整列表可在/etc/services中找到。

解决方法2:手动将端口写入sockaddr

如果您不使用来自/etc/services的端口号,您可以手动将正确的端口号写入您的struct sockaddr。如果这样做,重要的是:

sockaddr使用网络字节顺序,因此您需要使用htons()来转换您的端口号。

以下是应用于您的示例的解决方法:

代码语言:javascript
运行
复制
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));
    }
}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37386161

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档