2015-10-23 77 views
1

我要疯了在python中编写一个小套接字服务器。一切工作正常,但我注意到,在客户端刚刚消失的情况下,服务器无法辨别。我通过拉动客户端和服务器之间的以太网电缆来模拟这一点,关闭客户端,然后重新插入电缆。服务器从不会听到客户端断开连接,并且将永远等待,从不允许更多客户端连接。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 

心跳的sendall不会抛出一个异常,recv的唯一抛出超时(或其他异常,如果客户能够正确地关闭下正常连接情况)。

任何想法?我错了,发送给一个没有ACK的客户端最终会产生一个异常(我测试了几分钟)。

+0

它应该失败........最终...当系统合理确信没有可行路线存在。由于可行的链路可能涉及拨号调制解调器或信鸽等缺陷,这可能需要很长时间。如您所怀疑的那样,应用程序级轮询/确认通常用于在“安静”间隔期间监视可达性,而不会在对等端之间交换其他数据。 –

+0

另外'服务器从不会听到客户端断开连接,并且将永远等待,永远不会允许更多的客户端连接。' - 指出您的服务器设计存在严重问题。一个卡住/ AWOL客户端不应该阻止他人连接/通信! –

回答

0

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

假设服务器的套接字有待发送的数据,TCP堆栈将最终(即几分钟后)确定没有数据经过足够长的时间,并且单方面关闭连接。因此,如果您的问题检测时间只有几分钟,那么避免僵尸连接问题的最简单方法就是确保周期性地通过TCP连接发送一些心跳数据,正如您所描述的那样。当TCP堆栈试图(并反复失败)获取发送和确认的传出数据时,最终会触发它关闭连接。

如果你想要比这更快的东西,你需要用超时实现你自己的质询/响应系统(通过TCP套接字,或通过单独的TCP套接字,或通过UDP),但请注意,在做所以你很可能自己受到误报(例如,你最终可能会断开一个并非实际死亡的TCP连接,而只是由于拥塞导致暂时丢失数据包)。这是否值得权衡取决于你正在编写什么类型的程序。 (还要注意,UDP有它自己的问题,特别是如果你希望你的系统跨防火墙工作等)

相关问题