gpt4 book ai didi

c - 为什么设置 AI_PASSIVE 时 getaddrinfo() 返回第一个 IPv4 而不是 IPv6?

转载 作者:行者123 更新时间:2023-12-03 12:07:10 27 4
gpt4 key购买 nike

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

This statement in the POSIX specification also implies that if the AI_PASSIVEflag is specified without a hostname, then the IPv6 wildcard address (IN6ADDR_ANY_INIT or 0::0) should be returned as a sockaddr_in6 structure,along with the IPv4 wildcard address (INADDR_ANY or 0.0.0.0), which isreturned as a sockaddr_in structure. It also makes sense to return the IPv6wildcard address first because we will see in Section 12.2 that an IPv6 serversocket can handle both IPv6 and IPv4 clients on a dual-stack host.


但是,如果我尝试设置 AI_PASSIVE标志(当然还有 null 主机名),就像被动服务器的情况一样,那么我将首先获得 IPv4而不是 IPv6正如书中建议的那样:
#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);
}
输出:
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 并因此返回客户端永远不会连接。那么如何让 getaddrinfo 在设置 AI_PASSIVE 时返回 0::0 而不是 0.0.0.0 呢?

最佳答案

getaddrinfo 的预期使用模型与 AI_PASSIVE是你绑定(bind)它返回监听的所有地址,而不仅仅是第一个。
至于为什么特定实现首先返回 v4 结果,我不确定。一个可能的动机是 v6 套接字的默认行为,用于接受 v4 连接的“任何”地址(通过 v4 映射地址)。如果您首先绑定(bind) v6,那么您可能会在第一次和第二次绑定(bind)之间获得此类 v4mapped 客户端。如果先绑定(bind) v4,则确保所有 v4 连接都在 v4 套接字上。如果 v6 any 已经绑定(bind),甚至可能绑定(bind) v4 失败。

关于c - 为什么设置 AI_PASSIVE 时 getaddrinfo() 返回第一个 IPv4 而不是 IPv6?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65888168/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com