我无法在特定网络中检测到套接字客户端关闭。我正在运行套接字服务器,一旦客户端连接,我正在保存客户端套接字并定期向客户端发送请求。我正在使用select.poll然后检查是否有任何数据要从套接字读取,如果有,将从套接字读取。到目前为止,这一切都很好。
问题是,如果远程套接字客户端被终止,将选择.poll信号在客户端套接字中读取事件。如果发生这种情况,那么我可以检查socket.recv中返回的数据长度,以检测客户端是否已断开连接 - as is described here
为select
添加代码段 def _wait_for_socket_poller(self, read, write, message=None):
"""
Instead of blockign wait, this polls and check if the read or write socket is ready. If so it proceeds with
reading or writing to the socket. The advantage is that while the poll blocks, it yeilds back to the other
waiting greenlets; poll blocks because we have not given a timeout
:param read: The read function
:param write: The write function
:param message: The CrowdBox API call
:return: The result : In case of read - In JSON format; But catch is that the caller cannot wait on the
result being available,as else the thread will block
"""
if not self.client_socket:
logging.error("CB ID =%d - Connection closed", self.id)
return
poller = select.poll()
# Commonly used flag setes
READ_ONLY = select.POLLIN | select.POLLPRI | select.POLLHUP | select.POLLERR
WRITE_ONLY = select.POLLOUT
READ_WRITE = READ_ONLY | select.POLLOUT
if read and write:
poller.register(self.client_socket, READ_WRITE)
elif write:
poller.register(self.client_socket, WRITE_ONLY)
elif read:
poller.register(self.client_socket, READ_ONLY)
# Map file descriptors to socket objects
fd_to_socket = {self.client_socket.fileno(): self.client_socket, }
result = ''
retry = True
while retry:
# Poll will Block!!
events = poller.poll(
1) # using poll instead of select as the latter runs out of file descriptors on load
# Note here, Poll needs to timeout or will block ,as there is no gevent patched poll, the moment it blocks
# neither greenlets or Twisted Deffered can help -Everything freezes,as all of this is in main thread
if not events:
retry = True
gevent.sleep(0) # This is needed to yeild in case no input comes from CB
else:
retry = False
clientsock = None
fd = None
flag = None
for fd, flag in events:
# Retrieve the actual socket from its file descriptor to map return of poll to socket
clientsock = fd_to_socket[fd]
if clientsock is None:
logging.error("Problem Houston")
raise ValueError("Client Sokcet has Become Invalid")
if flag & select.POLLHUP:
logging.error("Client Socket Closed")
self.client_socket.close()
self.client_socket = None
return None
if flag & (select.POLLIN | select.POLLPRI):
if read:
result = read()
if flag & select.POLLOUT:
if write:
result = write(message)
# poller.uregister(self.client_socket)
return result
答案 0 :(得分:0)
通常,是的,套接字将被标记为"可读"当TCP连接关闭时。但这假设正常关闭,意味着TCP FIN或RST数据包。
有时TCP连接不会以这种方式结束。特别是,如果未启用TCP Keep-Alive(并且默认情况下不启用),则服务器和客户端之间的网络中断可以有效地终止连接,而无需任何一方知道,直到他们尝试发送数据。
因此,如果您想确保在TCP连接断开时立即得到通知,则需要在TCP层或应用层发送保持活动消息。
保持活动消息具有额外的好处,可以防止未使用的连接因长时间不活动而被各种网络设备自动丢弃。
有关保持活力的更多信息,请参阅此处:http://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html
答案 1 :(得分:0)
想在这里添加一个anwer,以便我可以发布一些tcp转储跟踪。我们在实时网络中对此进行了测试。远程计算机中的Socket客户端进程终止,并且python socket.send
(在非阻塞套接字上)client_socket.setblocking(0)
没有返回任何错误,因为后续请求从服务器发送到客户端没有生成事件表示(EPOLLIN)要读的东西。
因此,为了检测客户端连接丢失,我们会定期ping客户端,如果三次重试后没有预期的响应,请断开客户端连接。基本上在应用程序层中处理这个问题。客户也改为回复我们的“你还活着”请求的一些数据而不是忽略它。
sent = 0
try:
sent = self.client_socket.send(out)
except socket.error as e:
if e.args[0] == errno.EPIPE:
logging.error("Socket connection is closed or broken")
if sent == 0 and self.client_socket is not None:
logging.error("socket connection is already closed by client, cannot write request")
self.close_socket_connection()
else
# send succcessfully