根据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:
#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,因此客户端永远不会连接。那么,在设置AI_PASSIVE时,如何使getaddrinfo返回0::0而不是0.0.0.0?
发布于 2021-01-25 16:39:17
getaddrinfo与AI_PASSIVE的预期使用模型是绑定它返回的所有地址以侦听,而不是仅仅绑定第一个地址。
至于为什么某个特定的实现首先返回v4结果,我不确定。一个合理的动机是接受v4连接的“任意”地址的v4套接字的默认行为(通过v4mapped地址)。如果首先绑定v6,则有可能在第一个绑定和第二个绑定之间获得这样的v4mapped客户端。如果首先绑定v4,则确保所有v4连接都来自v4套接字。如果已经绑定了v4,那么绑定v6甚至可能会失败。
https://stackoverflow.com/questions/65888168
复制相似问题