Python 3 - 带有select.select()的套接字 - 检测连接丢失

时间:2015-01-24 19:46:12

标签: python sockets python-3.x tcp

我有一个运行TCP套接字服务器的Python 3服务器脚本,使用select.select()检测并响应传入的数据

我使用select.select()处理多个连接而没有线程,服务器主要是被动的(只等待数据并响应)。它为另一端的每个连接和设备参数保留一个字典;每个设备的条目在其连接关闭时被删除。

我的问题是我的客户端有时会在没有实际关闭TCP套接字的情况下丢失连接,我无法解决如何捕获或创建超时以关闭套接字并从字典中删除旧连接。

有没有好办法呢?

这是脚本的简化副本:

host = '192.168.0.252'
port = 9989
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind((host,port))
server.listen(16)
socks = [server]
devices = {}

while True:
  readable,writable,exceptionavailable = select.select(socks,[],[])
  for s in readable:
    if(s == server):
      client, address = server.accept()
      socks.append(client)
    else:
      try: data = s.recv(1024)
      except ConnectionResetError: data = 0

      if data:
        print(data) # Would append device to "devices" dictionary
      else:
        s.close()
        socks.remove(s)
        del(devices[did]) # did is the ID that needs deleting from dictionary

非常感谢任何帮助。

1 个答案:

答案 0 :(得分:2)

修改:根据@ Daniel的评论更新了更好的代码。

如果您在X秒内无法读取连接,请假设您要关闭连接。然后你必须:

  1. 对于每个套接字,记录您上次读取它的时间。
  2. 每次选择返回更新上次读取时间并关闭已超时的连接。
  3. 在此代码中,连接的超时设置为300秒。

    lastread = {} # a dictionary with sockets as keys
    ...
    
    readable,_,_ = select.select(socks,[],[], 60)
    now = time()
    for s in readable:
      ... read from the socket s and process input ...
      lastread[s] = now
    closed = []
    for s in lastread:
      if s not in readable and now - lastread[s] > 300:
        ... close connection ...
        closed.append(s)
    for s in closed: del lastread[s]
    

    注意:

    1. 传递给select的超时(在这种情况下为60)与连接超时没有多大关系。它只是说你希望在最多60秒之后将控制权交给你。
    2. 确保在创建套接字lastread[s]时初始化s,并在关闭连接时删除密钥。
    3. 更多资源:

      • 使用select并暂停(link)
      • 的教程
      • 讨论丢弃的TCP连接问题和其他一些解决方案的文章:(link)