【发布时间】:2019-01-29 22:21:28
【问题描述】:
我想要一个等待客户端连接的 TCP 服务器,一旦它们连接,就会不断地向它们发送一些数据。我还希望服务器能够注意到客户端是否突然消失而无影无踪,并将其从打开的套接字列表中删除。
我的代码如下所示:
#!/usr/bin/env python3
import select, socket
# Listen Port
LISTEN_PORT = 1234
# Create socket
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Setup the socket
server.setblocking(0)
server.bind(('0.0.0.0', LISTEN_PORT))
server.listen(5)
# Make socket reusable
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# Setup TCP Keepalive
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)
# Tell user we are listening
print("Listening on port %s" % LISTEN_PORT)
inputs = [server]
outputs = []
while True:
# Detecting clients that disappeared does NOT work when we ARE
# watching if any sockets are writable
#readable, writable, exceptional = select.select(inputs, outputs, inputs)
# Detecting clients that disappeared works when we aren't watching
# if any sockets are writable
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)
outputs.append(connection)
else:
try:
data = s.recv(1024)
except TimeoutError:
print("Client dropped out")
inputs.remove(s)
if s in outputs:
outputs.remove(s)
continue
if data:
print("Data from %s: %s" % (s.getpeername(), data.decode('ascii').rstrip()))
else:
print("%s disconnected" % (s.getpeername(),))
for s in writable:
s.send(b".")
如您所见,我正在使用 TCP Keepalive 来查看客户端是否已消失。我看到的问题是这样的:
- 当我没有 select() 监视可写套接字时,当客户端消失时,select() 将在 TCP Keepalive 超时到期后停止阻塞,并且套接字将在
readable列表中,所以我可以删除从input和output消失的客户端(这很好) - 当我让 select() 监视可写套接字时,当客户端消失时,select() 在 TCP Keepalive 超时到期后不会停止阻塞,并且客户端套接字永远不会在
readable或writable中结束列表,所以它永远不会被删除
我正在使用来自不同机器的 telnet 作为客户端。为了复制消失的客户端,我使用 iptables 来阻止客户端在客户端连接时与服务器通信。
有人知道怎么回事吗?
【问题讨论】:
-
因为是连续发送,所以根本不需要 TCP keepalive。如果客户端消失,您最终将重置连接。而且你不需要在写作之前选择可写性。只需编写,并且仅在产生 EAGAIN/EWOULDBLOCK 时使用
select()。注意使用iptables不会模拟消失的客户端。 -
1.即使是一个简单的单线程 python 应用程序,它等待单个客户端连接并不停地写入它也不会注意到客户端在 5 分钟后消失(我刚刚尝试过)。 2. iptables 确保客户端没有机会向服务器发出断开连接的信号。不拔网线就好了 3. 如果我不使用 select() 来检查可写性,我最终只检查新连接,看起来像this,在这种情况下,选择。 select 将阻塞,阻止写入。我错过了什么吗?
-
我在五分钟内什么都没说,但它肯定会发生。你可以随时写。你不需要
select()'permission`,除非我提到的情况。
标签: python-3.x sockets networking