【问题标题】:How to use python socket.settimeout() properly如何正确使用 python socket.settimeout()
【发布时间】:2016-03-26 01:49:57
【问题描述】:

据我所知,当您调用 socket.settimeout(value) 并设置大于 0.0 的浮点值时,当调用 socket.recv 必须等待比指定的值。

但是假设我必须接收大量数据,并且必须多次调用recv(),那么 settimeout 对此有何影响?

给定以下代码:

to_receive = # an integer representing the bytes we want to receive
socket = # a connected socket

socket.settimeout(20)
received = 0
received_data = b""

while received < to_receive:
    tmp = socket.recv(4096)
    if len(tmp) == 0:
        raise Exception()
    received += len(tmp)
    received_data += tmp

socket.settimeout(None)

代码的第三行将套接字的超时设置为 20 秒。每次迭代都会重置超时吗?只有当其中一次迭代花费超过 20 秒时才会引发超时?

A) 如果接收所有预期数据的时间超过 20 秒,我如何对其进行重新编码以引发异常?

B) 如果我在读取所有数据后没有将超时设置为无,会发生什么不好的事情吗? (连接保持活动状态,将来可能会请求更多数据)。

【问题讨论】:

    标签: python sockets tcp


    【解决方案1】:

    超时适用于每次调用 recv()。

    A) 只需使用您现有的超时并调用 recv(to_receive) - 即尝试在一个 recv 调用中接收所有数据 - 实际上我不明白为什么您不应该将其用作默认工作方式

    B) 不会发生任何不好的事情,但是使用该套接字的任何其他代码都需要注意处理超时。

    在您现有的代码中,recv() 调用不应该是 recv(max(4096,to_receive-received)) - 这样您就不会无意中消耗 to_receive 字节之后的任何数据。

    【讨论】:

      【解决方案2】:

      超时独立应用于对套接字读/写操作的每个调用。所以下一次调用将是 20 秒。

      A) 要让多个后续调用共享超时,您必须手动跟踪它。大致如下:

      deadline = time.time() + 20.0
      while not data_received:
          if time.time() >= deadline:
              raise Exception() # ...
          socket.settimeout(deadline - time.time())
          socket.read() # ...
      

      B) 任何使用超时套接字且尚未准备好处理socket.timeout 异常的代码都可能会失败。在开始操作之前记住套接字的超时值更可靠,并在完成后恢复它:

      def my_socket_function(socket, ...):
          # some initialization and stuff
          old_timeout = socket.gettimeout() # Save
          # do your stuff with socket
          socket.settimeout(old_timeout) # Restore
          # etc
      

      这样,您的函数将不会影响调用它的代码的功能,无论它们中的任何一个对套接字超时做什么。

      【讨论】:

        【解决方案3】:

        查看我的服务器脚本,你就会知道如何正确使用它。

        import socket
        import sys
        fragments = []
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.bind(("192.168.1.4",9001))
        s.listen(5)
        while True:
            c,a = s.accept()
            c.settimeout(10.0)
            print "Someone came in Server from %s and port %s" %(a[0],a[1])
            c.send("Welcome to system")
            while True:
                chunk = c.recv(2048)
                if not chunk.strip():
                    break
                else:
                    fragments.append(chunk)
                    continue
            combiner = "".join(fragments)
            print combiner
            shutdown = str(raw_input("Wanna Quit(Y/y) or (N/n): "))
            if shutdown == 'Y' or shutdown == 'y':
                c.close()
                sys.exit()
            else:
                continue
        

        这个脚本只是为了让你了解socket.settimeout()。

        【讨论】:

        • 它看起来确实在 10 秒后进入阻塞状态。但不确定它为什么有用。如果不使用 settimeout 会发生什么?
        【解决方案4】:

        https://docs.python.org/3/library/socket.html#socket.socket.settimeout

        “在 3.5 版更改:每次成功发送数据时不再重置套接字超时。套接字超时现在是发送所有数据的最大总持续时间。”

        【讨论】:

        • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review
        猜你喜欢
        • 2017-08-20
        • 1970-01-01
        • 1970-01-01
        • 2014-09-17
        • 2021-09-14
        • 1970-01-01
        • 1970-01-01
        • 2021-07-31
        • 2019-05-23
        相关资源
        最近更新 更多