Py学习  »  Python

如何检测TCP客户端何时与Python的选择(?)断开连接?

John • 5 年前 • 1852 次点击  

我有一个使用select()的简单服务器,如下所示:

#!/usr/bin/env python2

import select, socket

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setblocking(0)
server.bind(('localhost', 50000))
server.listen(5)

# TCP Keepalive Options
#server.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
#server.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 1)
#server.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 3)
#server.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 5)

inputs = [server]

print "Listening on port 50000"

while True:
    readable, writable, exceptional = select.select(inputs, [], inputs)

    for s in readable:
        if s is server:
            connection, client_address = s.accept()
            print "New client connected: %s" % (client_address,)

            connection.setblocking(0)
            inputs.append(connection)
        else:
            data = s.recv(1024)

            if data:
                print "Data from %s: %s" % (s.getpeername(), data.replace('\n', ''))
            else:
                print "%s disconnected" % (s.getpeername(),)

                inputs.remove(s)
                s.close()

    for s in exceptional:
        print "Client at %s dropped out" % (s.getpeername(),)
        inputs.remove(s)
        s.close()

我可以使用telnet客户机连接它,它工作得很好。它不响应客户机,但是对于这个简单的例子来说,这很好。

我看到的问题是:如果客户端在没有发送tcp fin或tcp rst的情况下断开连接,服务器似乎永远不会发现客户端已经不在了。

我通过这样做来模拟客户消失:

  • 运行服务器
  • 将telnet客户端连接到服务器
  • 使用iptables阻止telnet客户端与服务器对话

据我所知,通常的解决方案是打开tcp keepalive,这是通过取消对tcp keepalive部分的注释来实现的。 当我这样做,并遵循相同的测试过程,使客户端在连接会话的中间消失时,似乎当套接字 超时时,select()停止阻塞,并返回“可读”列表中的客户端(与异常列表相反)。这个 使我的服务器尝试使用s.recv(1024)从该套接字读取数据,这会使服务器崩溃(s.recv()抛出一个socket.error异常)。

我知道我可能会抓住例外并处理它,但我更好奇为什么:

  1. select()没有发现客户机消失的事实
    • 我认为select()将要寻找的最重要的异常类型之一是客户机是否消失。还是在寻找混乱的输入?
  2. 即使我显式地启用了tcp keepalive,select()仍然将超时的套接字放入可读列表,而不是异常列表

这是预期的吗?有没有办法让select()将消失在异常列表中的客户机放在异常列表中?或者,重要的是不要仅仅因为select()说套接字已经准备好读取,就认为recv()不会失败?

编辑:这个问题不是我刚才问的问题的重复 here ,因为这个函数专门处理select(),以及它如何处理异常。这一个实际上包含了我从另一个问题中学到的代码。

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/43491
 
1852 次点击  
文章 [ 1 ]  |  最新文章 5 年前