【问题标题】:Python's 2.7 socket.timeout behaviorPython 2.7 socket.timeout 行为
【发布时间】:2015-11-03 15:58:43
【问题描述】:

下面是两个简单的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 服务器,而不是来自套接字模块。

【问题讨论】:

    标签: python python-2.7 sockets


    【解决方案1】:

    首先,您可以将您的 to 函数统一为:

    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 倍。

    【讨论】:

      猜你喜欢
      • 2016-07-24
      • 2018-04-21
      • 2017-04-11
      • 2019-04-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-15
      相关资源
      最近更新 更多