使用带有AI_PASSIVE的getaddrinfo()

glg*_*lgl 6 sockets serversocket getaddrinfo

getaddrinfo()函数不仅允许客户端程序有效地找到用于创建给定主机的套接字的正确数据,它还允许服务器绑定到正确的套接字 - 理论上.

我刚刚了解了这一点并开始通过Python来解决它:

from socket import *
for i in getaddrinfo(None, 22, AF_UNSPEC, SOCK_STREAM, IPPROTO_IP, AI_PASSIVE): i
Run Code Online (Sandbox Code Playgroud)

产量

(2, 1, 6, '', ('0.0.0.0', 22))
(10, 1, 6, '', ('::', 22, 0, 0))
Run Code Online (Sandbox Code Playgroud)

是什么让我想知道是否有什么不对劲.

我应该对这些答案究竟做些什么?我是不是该

  • 制作listen()所有这些答案的插座,或者我应该
  • 只选择真正有效的第一个?

联机帮助页中的示例建议我只选择第一个并且如果它没有错误就对它感到满意,但在我的示例中我只通过IPv4获得连接.

但是,如果我尝试所有这些,我不得不担心2个服务器套接字,这是不必要的,因为如果满足某些条件(OS,套接字标志等),IPv6服务器套接字也会监听IPv4.

我错在哪里?


编辑:很明显,我没想错,但我的电脑做错了.我使用/etc/gai.confOpenSUSE附带的默认值.如果有人能指出我正确的方向,那将是很好的.

编辑2:在给定的情况下,strace在读取后给出内部进行的以下调用/etc/gai.conf(现在使用端口54321,因为我认为使用端口22可能会产生一些不良影响,但事实并非如此):

socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP) = 3
connect(3, {sa_family=AF_INET6, sin6_port=htons(54321), inet_pton(AF_INET6, "::", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, 28) = 0
getsockname(3, {sa_family=AF_INET6, sin6_port=htons(38289), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, [28]) = 0
connect(3, {sa_family=AF_UNSPEC, sa_data="\0\0\0\0\0\0\0\0\0\0\0\0\0\0"}, 16) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(54321), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
getsockname(3, {sa_family=AF_INET6, sin6_port=htons(60866), inet_pton(AF_INET6, "::ffff:127.0.0.1", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, [28]) = 0
close(3)                                = 0
Run Code Online (Sandbox Code Playgroud)

显然,决定是根据getsockname()电话的结果进行的......

BTW:https://bugs.launchpad.net/ubuntu/+source/eglibc/+bug/673708以及其他提到的错误报告确认了我的观察结果.有几个人声称新行为是正确的,所以我显然坚持使用AF_INET6...... :-(

Per*_*son 4

由于某种原因,您getaddrinfo返回了错误的结果。它应该首先返回 IPv6 套接字。我唯一能想到的是,如果您的操作系统检测到您的系统具有低优先级 IPv6(6to4 或 Teredo)并避免它们,在我看来,在这种情况下是错误的。编辑:刚刚注意到我自己的电脑也做了同样的事情,我使用 6to4。

但是,您可以同时听它们,也可以AF_INET6使用AF_UNSPEC. 然后你可以执行setsockopt来禁用IPV6_V6ONLY

getaddrinfo 在这里做了合理的事情并返回所有适用的结果(尽管顺序错误,正如我提到的)。一个和两个监听套接字都是有效的方法,具体取决于您的应用程序。