【发布时间】:2011-12-28 04:00:13
【问题描述】:
getaddrinfo() 函数不仅允许客户端程序有效地找到正确的数据以创建到给定主机的套接字,它还允许服务器绑定到正确的套接字 - 理论上。
我只是 learned about that 并开始通过 Python 玩弄它:
from socket import *
for i in getaddrinfo(None, 22, AF_UNSPEC, SOCK_STREAM, IPPROTO_IP, AI_PASSIVE): i
产量
(2, 1, 6, '', ('0.0.0.0', 22))
(10, 1, 6, '', ('::', 22, 0, 0))
是什么让我怀疑是否有问题。
我究竟应该如何处理这些答案?我应该
- 为所有这些答案创建一个
listen()ing 套接字,或者我应该这样做 - 只选择第一个真正有效的?
manpage 中的示例建议我只使用第一个,如果它没有错误,我会对此感到满意,但是在我的示例中,我只能通过 IPv4 获得连接。
但是如果我尝试所有这些,我不得不担心 2 个服务器套接字,这是不必要的,因为如果满足某些条件(操作系统、套接字标志等), IPv6 服务器套接字也会监听 IPv4。
我哪里想错了?
编辑:显然,我没有想错,但我的电脑做错了事。我使用 OpenSUSE 附带的默认 /etc/gai.conf。如果有人能指出我正确的方向,那就太好了。
编辑 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
显然,该决定旨在根据getsockname() 调用的结果进行...
顺便说一句:https://bugs.launchpad.net/ubuntu/+source/eglibc/+bug/673708 和那里提到的其他错误报告证实了我的观察。那里有几个人声称新行为是正确的,所以我显然坚持使用AF_INET6... :-(
【问题讨论】:
-
最简单的方法就是在调用bind()时将INADDR_ANY作为IP地址传递,然后你就有了一个监听所有接口的socket,你就不用担心了关于 getaddrinfo() 或多个监听套接字。
-
但是使用
INADDR_ANY我仅限于 IPv4。我想介绍 IPv6 和 IPv4。 -
那是不正确的....对于 IPv6,有一个常量 in6addr_any 的工作方式相同。 (实际上,这两个常量都只是更易读的零名称;指定要绑定的零地址会给您带来通配符行为)此处的示例代码:publib.boulder.ibm.com/infocenter/iseries/v5r3/…
-
我确定我已经读过它指定应该首先返回
AF_INET6,但现在我找不到了。所以我想我可能弄错了。
标签: sockets serversocket getaddrinfo