python通过select控制死插座的故障
我有一些代码,它将连接到主机,只监听传入数据,直到客户端关闭或主机发送close语句。为此,我的代码运行良好 但是,当主机死亡而未发送close语句时,我的客户机将一如既往地侦听传入的数据。为了解决这个问题,我让套接字每foo秒超时一次,然后开始检查连接是否处于活动状态。从Python howto中,我发现: select有一个非常严重的问题:如果套接字输入列表中的某个地方是一个死气沉沉的套接字,select将失败。然后,您需要遍历所有这些列表中的每一个该死的套接字,并进行选择([sock],[],0),直到找到错误的套接字。超时值为0意味着不会花太长时间,但这很难看 本文提出三个问题python通过select控制死插座的故障,python,sockets,select,tcp,blocking,Python,Sockets,Select,Tcp,Blocking,我有一些代码,它将连接到主机,只监听传入数据,直到客户端关闭或主机发送close语句。为此,我的代码运行良好 但是,当主机死亡而未发送close语句时,我的客户机将一如既往地侦听传入的数据。为了解决这个问题,我让套接字每foo秒超时一次,然后开始检查连接是否处于活动状态。从Python howto中,我发现: select有一个非常严重的问题:如果套接字输入列表中的某个地方是一个死气沉沉的套接字,select将失败。然后,您需要遍历所有这些列表中的每一个该死的套接字,并进行选择([sock],[
gevent
、asyncore
和twisted
这样的库可以帮助我做到这一点,但我选择自己这样做是为了更好地了解正在发生的事情,并更好地控制自己的源代码
如果连接的客户端崩溃或退出,但其主机操作系统和计算机仍在运行,则其操作系统的TCP堆栈将向服务器发送一个FIN数据包,让计算机的TCP堆栈知道TCP连接已关闭。Python应用程序会将其视为select(),表示客户端的套接字已准备好读取,然后在套接字上调用recv()时,recv()将返回0。当这种情况发生时,您应该关闭套接字来响应
另一方面,如果连接的客户机的计算机从来没有机会发送FIN数据包(例如,因为有人伸手将其以太网线或电源线从插座中拔出),那么您的服务器将不会意识到TCP连接在相当长的一段时间内(可能永远)失效。避免“僵尸套接字”的最简单方法就是让服务器每隔一段时间(例如每分钟一次)在套接字上发送一些虚拟数据。客户机应该知道如何丢弃虚拟数据。发送虚拟数据的好处是,您的服务器的TCP堆栈随后会注意到,它没有为它发送的数据包返回任何ACK数据包,并将重新发送它们;在重新发送几次之后,服务器的TCP堆栈将放弃并确定连接已断开,此时您将看到与我在第一段中描述的相同的行为。我不确定Python howto是否正确,它必须循环所有套接字以确定哪一个已“死掉”。根据我的经验,select()只有在传递无效的文件描述符时才会失败,即使远程对等方突然断开连接的套接字在显式关闭之前仍然是完全有效的套接字。因此,请恕我直言。@JeremyFriesner我认为向死套接字写入数据会发现它死了(在尝试重新传输段后,客户端将关闭套接字并向服务器发送RST)。@Den是的,您是正确的。
# Example code written for this question.
from select import select
from socket include socket, AF_INET, SOCK_STREAM
socket = socket(AF_INET, SOCK_STREAM)
socket.connect(('localhost', 12345))
socklist = [socket,]
attempts = 0
def check_socklist(socks):
for sock in socklist:
(r, w, e) = select([sock,], [], [], 0)
...
...
...
while True:
(r, w, e) = select(socklist, [], [], 60)
for sock in r:
if sock is socket:
msg = sock.recv(4096)
if not msg:
attempts +=1
if attempts >= 10:
check_socket(socklist)
break
else:
attempts = 0
print msg