我有一个像这样的简单服务器:
#!/usr/bin/env python2
import socket
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('localhost', 50000))
server.listen(5)
# Set 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)
connection, client_address = server.accept()
while True:
try:
data = connection.recv(1024)
except socket.error:
print "%s dropped out" % (connection.getpeername(),)
break
if data:
print "%s: %s" % (connection.getpeername(), data)
else:
print "%s disconnected" % (connection.getpeername(),)
break
我使用TCP Keepalive来确定客户端是否消失(而不是正确断开连接) .
我看到的问题是,当客户端确实消失,并且我捕获了socket.error异常时,我的print语句尝试通过使用connection.getpeername()来确定哪个客户端断开连接,这不再有效 . 它扔了一个
socket.error: [Errno 107] Transport endpoint is not connected
例外 .
在这个简单的示例中,只有一个客户端可以同时连接,但是使用更复杂的代码同时处理多个客户端,知道哪个客户端退出可能会很有用 .
一旦套接字断开连接,是否无法知道它先前连接到哪个 endpoints ?为什么 connection
对象在 connection.getpeername()
中没有保留客户端的IP /端口信息,即使客户端断开连接?这是因为 connection
对象可能是可重用的吗?
如何使我的代码实际工作,并打印出哪个客户端退出?我是否需要将 connection.getpeername()
的输出存储在变量中,以便稍后再调用它?这意味着如果我有多个客户端,我需要为列表中的每个客户端存储 connection.getpeername()
值?
我知道使用 socket
是相当低的水平,我很确定使用 SocketServer.TCPServer
在真正的单词中会更容易 - 我只是想了解所涉及的低级网络 .
1 回答
遗憾的是,这是OS界面的限制 . 在已知套接字断开连接后,二进制(C)程序也无法获取对等名称 . 这是一种不幸的疣 . 您无法重新使用套接字进行新连接,因此无法检索's no good reason I can think of why the peer name couldn',但是......它不能 .
第一个想法是使用单独的
dict
与套接字对象作为密钥,通过它您可以查找关联的客户端地址:第二个是创建一个单独的类来包装套接字 . 该类可以保存从
accept
获得的对等地址,并在需要时将其返回给您 . 与此同时,它可以透明地将所有其他操作委托给底层套接字 .示范: