2015-11-03 72 views
4

下面是两个简单的python函数。首先尝试连接到666上的test.com域(主机名有效,但端口不是)。其次尝试在端口993上连接到imap.mail.outlook.com(主机名有效,但看起来不适合公共使用/访问)。Python的2.7 socket.timeout行为

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.comtimeout参数指定的连接将在〜同一时间后超时。但对于imap.mail.outlook.com事情变得有趣 - 套接字连接忽略超时参数。准确地说 - 不要忽略,而是在更长一段时间之后总是超时连接。

我可能以为这种行为来自imap.mail.outlook.com服务器,而不是来自套接字模块。

回答

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_HOSTTEST_PORT

    socket.getaddrinfo("test.com", 666) 
    [(2, 0, 0, '', ('69.172.200.235', 666))] 
    
  • IMAP_HOSTIMAP_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_HOSTIMAP_PORT返回3个不同的地址(而TEST_HOSTTEST_PORT它只返回一个)。既然你指定它没有任何作用,它会尝试连接到它们,导致一般的超时比你指定的大3倍。