下面是两个简单的python函数。首先尝试在666上连接到test.com
域(主机名有效但端口不是)。第二次尝试连接到端口993上的imap.mail.outlook.com
(主机名有效,但看起来不适合公共使用/访问)。
def fn_outlook(timeout):
try:
socket.create_connection(("imap.mail.outlook.com", 993), timeout=timeout)
except socket.timeout:
pass
def fn_test(timeout):
try:
socket.create_connection(("test.com", 666), timeout=timeout)
except socket.timeout:
pass
以下是具有不同超时的该函数的执行时间:
In [14]: %time fn_test(1)
CPU times: user 644 µs, sys: 1.07 ms, total: 1.71 ms
Wall time: 1 s
In [15]: %time fn_test(2)
CPU times: user 589 µs, sys: 1.15 ms, total: 1.74 ms
Wall time: 2 s
In [16]: %time fn_outlook(2)
CPU times: user 838 µs, sys: 2.24 ms, total: 3.08 ms
Wall time: 7.15 s
In [17]: %time fn_outlook(4)
CPU times: user 705 µs, sys: 1.18 ms, total: 1.88 ms
Wall time: 12 s
In [18]: %time fn_test(4)
CPU times: user 483 µs, sys: 795 µs, total: 1.28 ms
Wall time: 4.42 s
test.com
连接将在timeout
参数中指定的〜同一时间后超时。但是对于imap.mail.outlook.com
事情变得越来越有趣 - 套接字连接会忽略超时参数。确切地说 - 不要忽视,而是在更长的一段时间后总是超时连接。
我可能认为此行为源自imap.mail.outlook.com
服务器,而不是来自套接字模块。
答案 0 :(得分:4)
首先,您可以将您的功能统一为:
def fn_connect(host, port, timeout):
try:
s = socket.create_connection((host, port), timeout=timeout)
except socket.timeout:
return None
else:
return s
并将其称为:
IMAP_HOST = "imap.mail.outlook.com"
IMAP_PORT = 993
TEST_HOST = "test.com"
TEST_PORT = 666
s1 = fn_connect(IMAP_HOST, IMAP_PORT, 2)
s2 = fn_connect(TEST_HOST, TEST_PORT, 1)
#and so on....
我退回套接字后可以正常关闭它(如果是not None
)。
问题在于底层套接字机制如何解析主机名; create_connection
调用getaddrinfo,并且对于返回的每个地址,它会尝试创建一个套接字并连接到它(,每个套接字都有你指定的超时)。那么,你的2个地址的结果是:
TEST_HOST , TEST_PORT
socket.getaddrinfo("test.com", 666)
[(2, 0, 0, '', ('69.172.200.235', 666))]
IMAP_HOST , IMAP_PORT
socket.getaddrinfo("imap.mail.outlook.com", 993)
[(2, 0, 0, '', ('207.46.163.247', 993)),
(2, 0, 0, '', ('207.46.163.138', 993)),
(2, 0, 0, '', ('207.46.163.215', 993))]
如您所见,对于 IMAP_HOST , IMAP_PORT ,它会返回3个单独的地址(而对于 TEST_HOST , TEST_PORT 它只返回一个)。由于您指定它们都不起作用,它将尝试连接到所有它们,导致一般超时〜比您指定的大3倍。