2015-11-03 61 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倍。