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

2024-05-17 05:04:25 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个Python3服务器脚本,它运行一个TCP套接字服务器,使用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

任何帮助都将不胜感激。


Tags: 数据服务器脚本hostdataif字典server
1条回答
网友
1楼 · 发布于 2024-05-17 05:04:25

编辑:根据@Daniel的评论更新了更好的代码。

假设你想关闭一个连接,如果你在X秒内没有读取到它。那么你必须:

  1. 每一个插座都记录下你最后一次读到的内容。
  2. 每次选择返回更新上次读取时间并关闭超时的连接。

在此代码中,连接的超时设置为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],并在关闭连接时删除密钥。

更多资源:

  • 关于超时使用select的教程(link)
  • 一篇讨论丢弃的TCP连接问题和其他一些解决方案的文章:(link)

相关问题 更多 >