首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么在设置IPv4时,getaddrinfo()首先返回AI_PASSIVE而不是IPv6?

为什么在设置IPv4时,getaddrinfo()首先返回AI_PASSIVE而不是IPv6?
EN

Stack Overflow用户
提问于 2021-01-25 15:58:21
回答 1查看 379关注 0票数 1

根据https://www.amazon.com/Unix-Network-Programming-Sockets-Networking/dp/0131411551

POSIX规范中的这条语句还意味着,如果指定AI_PASSIVE标志时没有主机名,那么IPv6通配符地址(IN6ADDR_ANY_INIT或0:0)应该作为sockaddr_in6结构返回,以及IPv4通配符地址(INADDR_ANY或0.0.0.0),后者作为sockaddr_in结构返回。首先返回IPv6通配符地址也是有意义的,因为我们将在第12.2节中看到,IPv6服务器套接字可以在双堆栈主机上同时处理IPv6和IPv4客户端。

但是,如果我尝试设置AI_PASSIVE标志(当然还有null主机名),就像被动服务器的情况一样,那么我将得到第一个IPv4,而不是像书中所建议的IPv6

代码语言:javascript
复制
#include <netdb.h>
#include <stdio.h>
#include <sys/socket.h>
#include <string.h>
#include <arpa/inet.h>

#define HOSTLEN 128
#define PORTLEN 16

int main()
{
    int retcode;
    struct addrinfo hints, *res;
    char output[HOSTLEN], portbuf[PORTLEN];

    memset(&hints, 0, sizeof(hints));
    hints.ai_flags = AI_PASSIVE;
    hints.ai_family = AF_UNSPEC;
    //exmaple of socktype to be SOCK_STREAM
    hints.ai_socktype = SOCK_STREAM;

    //example port "ftp"
    if ((retcode = getaddrinfo(NULL, "ftp", &hints, &res)) != 0)
    {
        printf("getaddrinfo error: %s\n", gai_strerror(retcode));
    }

    do
    {
        switch (res->ai_family)
        {
        case AF_INET:;
            struct sockaddr_in *sin = (struct sockaddr_in *)res->ai_addr;
            inet_ntop(res->ai_family, &sin->sin_addr, output, HOSTLEN);
            snprintf(portbuf, PORTLEN, ":%d", ntohs(sin->sin_port));
            strcat(output, portbuf);
            break;

        case AF_INET6:;
            struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)res->ai_addr;
            output[0] = '[';
            inet_ntop(res->ai_family, &sin6->sin6_addr, output + 1, HOSTLEN - 1);
            snprintf(portbuf, PORTLEN, "]:%d", ntohs(sin6->sin6_port));
            strcat(output, portbuf);
            break;
        }

        printf("address returned from getaddrinfo: %s\n", output);
    } while ((res = res->ai_next) != NULL);
}

输出

代码语言:javascript
复制
address returned from getaddrinfo: 0.0.0.0:21
address returned from getaddrinfo: [::]:21

因此,我可以看到,getaddrinfo()的第一个地址是sockaddr_in(ipv4),而不是sockaddr_in6(ipv6)。那么,这本书是不正确的,还是仅仅因为一些配置?

我问的原因是,当试图连接客户端时,它会导致问题,它指定服务器的IPv6地址(服务器的地址是从getaddrinfo()返回的,设置为AI_PASSIVE),如果0:0,则返回0.0.0.0,因此客户端永远不会连接。那么,在设置AI_PASSIVE时,如何使getaddrinfo返回0::0而不是0.0.0.0?

EN

回答 1

Stack Overflow用户

发布于 2021-01-25 16:39:17

getaddrinfoAI_PASSIVE的预期使用模型是绑定它返回的所有地址以侦听,而不是仅仅绑定第一个地址。

至于为什么某个特定的实现首先返回v4结果,我不确定。一个合理的动机是接受v4连接的“任意”地址的v4套接字的默认行为(通过v4mapped地址)。如果首先绑定v6,则有可能在第一个绑定和第二个绑定之间获得这样的v4mapped客户端。如果首先绑定v4,则确保所有v4连接都来自v4套接字。如果已经绑定了v4,那么绑定v6甚至可能会失败。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65888168

复制
相关文章

相似问题

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