Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/347.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python套接字客户端消失,服务器无法分辨_Python_Sockets_Network Programming - Fatal编程技术网

Python套接字客户端消失,服务器无法分辨

Python套接字客户端消失,服务器无法分辨,python,sockets,network-programming,Python,Sockets,Network Programming,我正在疯狂地用python编写一个小套接字服务器。一切正常,但我注意到,在客户端消失的情况下,服务器无法判断。我通过拉动客户端和服务器之间的以太网电缆,关闭客户端,然后重新插入电缆来模拟这种情况。服务器从未听到客户端断开连接,将永远等待,永远不允许更多客户端连接 我想我应该通过给读取循环添加一个超时来解决这个问题,这样它就会尝试每10秒读取一次。我想,如果它尝试从套接字读取数据,可能会发现客户端丢失了。但后来我意识到服务器真的没有办法知道这一点 所以我加了一个心跳。如果服务器10秒不读取数据,它

我正在疯狂地用python编写一个小套接字服务器。一切正常,但我注意到,在客户端消失的情况下,服务器无法判断。我通过拉动客户端和服务器之间的以太网电缆,关闭客户端,然后重新插入电缆来模拟这种情况。服务器从未听到客户端断开连接,将永远等待,永远不允许更多客户端连接

我想我应该通过给读取循环添加一个超时来解决这个问题,这样它就会尝试每10秒读取一次。我想,如果它尝试从套接字读取数据,可能会发现客户端丢失了。但后来我意识到服务器真的没有办法知道这一点

所以我加了一个心跳。如果服务器10秒不读取数据,它将向客户端发送数据。然而,即使这样也很成功(这意味着不会抛出任何类型的异常)。因此,我能够对不再存在的客户机进行读写操作。是否有任何方法可以知道客户机已经离开,而不在客户机和服务器之间实现某种质询/响应协议?在这种情况下,这将是一个突破性的变化,我想避免它

以下是我的代码的核心:

  def _loop(self):
      command = ""
      while True:
          socket, address = self._listen_socket.accept()
          self._socket = socket
          self._socket.settimeout(10)
          socket.sendall("Welcome\r\n\r\n")
          while True:
              try:
                  data = socket.recv(1)
              except timeout: # Went 10 seconds without data
                  pass
              except Exception as e: # Likely the client closed the connection
                 break
             if data:
                 command = command + data
                 if data == "\n" or data == "\r":
                     if len(command.strip()) > 0:
                         self._parse_command(command.strip(), socket)
                         command = ""
                 if data == '\x08':
                     command = command[:-2]
             else: # Timeout on read
                 try:
                     self._socket.sendall("event,heartbeat\r\n") # Send heartbeat
                 except:
                     self._socket.close()
                     break
heartbeat的sendall从不抛出异常,recv只抛出超时(或者如果客户端在正常情况下正确关闭连接,则抛出另一个异常)


有什么想法吗?发送到未确认的客户端最终会生成异常(我已经测试了几分钟),这是我错了吗?

您观察到的行为是TCP套接字连接的预期行为。特别是,一般来说,TCP堆栈无法知道以太网电缆已被拔出或远程客户端程序(现在已物理断开)已关闭;它所知道的是,它已经停止接收来自远程对等方的确认数据包,并且它所知道的数据包可能只是被某个过载的路由器丢弃了,这个问题将在瞬间自行解决。有鉴于此,它做了TCP在其数据包未得到确认时通常做的事情:它降低了传输速率和飞行限制中的数据包数量,并重新传输未确认的数据包,希望它们这次能通过

假设服务器的套接字有挂起的传出数据,TCP堆栈将最终(即几分钟后)确定没有数据经过足够长的时间,并单方面关闭连接。因此,如果您对几分钟的问题检测时间感到满意,那么避免僵尸连接问题的最简单方法就是确保通过TCP连接定期发送一点心跳数据,如您所述。当TCP堆栈尝试(并且多次失败)获取发送和确认的传出数据时,这将最终触发它关闭连接


如果您想要更快的速度,您需要实现自己的带有超时的质询/响应系统(通过TCP套接字、或通过单独的TCP套接字、或通过UDP),但请注意,在这样做的过程中,您自己可能会遇到误报(例如,您可能最终切断了一个TCP连接,而该连接实际上并没有死机,只是由于拥塞而暂时出现了数据包丢失的情况)。这是否值得权衡,取决于您编写的程序类型。(还请注意,UDP有其自身的问题,特别是如果您希望您的系统跨防火墙工作等)

您观察到的行为是TCP套接字连接的预期行为。特别是,一般来说,TCP堆栈无法知道以太网电缆已拔出或(现在已物理断开连接)远程客户端程序已关闭;它所知道的只是它已停止接收来自远程对等方的确认数据包,并且它所知道的数据包可能只是被某个过载的路由器丢弃了,问题将立即自行解决。因此,它会像TCP在其数据包现在没有得到确认时所做的那样ledged:它降低了传输速率和飞行限制中的数据包数量,并重新传输未确认的数据包,希望它们这次能通过

假设服务器的套接字有挂起的传出数据,TCP堆栈最终将(即几分钟后)确定没有数据经过足够长的时间,然后单方面关闭连接。因此,如果您对几分钟的问题检测时间感到满意,那么避免僵尸连接问题的最简单方法就是确保定期通过TCP连接发送一点心跳数据,如您所述。当TCP停止时ck尝试(并多次失败)发送和确认传出数据,这最终将触发它关闭连接


如果您想要更快的速度,您需要实现自己的带有超时的质询/响应系统(通过TCP套接字、或通过单独的TCP套接字、或通过UDP),但请注意,在这样做的过程中,您自己可能会遇到误报(例如,您可能最终切断了一个TCP连接,而该连接实际上并没有死机,只是由于拥塞而暂时出现了数据包丢失的情况)。这是否值得权衡,取决于您编写的程序类型。(还请注意,UDP有其自身的问题,特别是如果您希望系统跨防火墙工作,等等)

它应该会失败……最终……当系统合理地确定不存在可行的路由时。由于可行的链路可能会涉及拨号调制解调器或信鸽等问题,这可能需要很长时间。正如您所怀疑的,应用程序级轮询/ack通常用于在“安静”时间间隔内监控可达性,而不需要其他数据中国