在套接字断开连接后,有没有办法在Python中获取peerName()?

在套接字断开连接后,有没有办法在Python中获取peerName()?,python,sockets,networking,Python,Sockets,Networking,我有这样一个简单的服务器: #!/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) serve

我有这样一个简单的服务器:

#!/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
例外

在这个简单的示例中,一次只能连接一个客户机,但是对于同时处理多个客户机的更复杂的代码,了解哪个客户机退出可能会很有用

一旦套接字断开连接,是否就无法知道它以前连接到了哪个端点? 为什么连接对象不在connection.getpeername中保留客户端的IP/端口信息, 甚至在客户端断开连接之后?这是因为连接对象可能是可重用的吗

我怎样才能使我的代码实际工作,并打印出哪个客户端退出?我是否需要将connection.getpeername的输出存储在变量中,以便以后调用它?这意味着如果我有多个 客户端,我需要为列表中的每个客户端存储connection.getpeername值


我知道使用socket是相当低级的,而且我很确定使用SocketServer.TCPServer实际上会更简单-我只是想了解涉及的低级网络。

不幸的是,这是操作系统接口的一个限制。在已知套接字已断开连接后,二进制C程序也将无法获取对等名称。这是一种不幸的疣。你不能为新的连接重复使用套接字,因此我想不出为什么无法检索对等名称,但是。。。不可能

第一个想法是使用单独的dict,将套接字对象用作键,通过它可以查找相关的客户端地址:

saved_addr = {}
...
connection, client_address = server.accept()
saved_addr[connection] = client_address`
while True:
    try:
        data = connection.recv(1024)
    except socket.error:
        print("{} disconnected".format(saved_addr[connection]))
第二种方法是创建一个单独的类来包装套接字。该类可以保存从accept获得的对等地址,并在需要时将其返回给您。同时,它可以透明地将所有其他操作委托给底层套接字

演示:

import socket
import time

class ConnectedSocket:
    def __init__(self, sock, peer):
        self.sock = sock
        self.peer = peer
    def get_peer(self):
        return self.peer
    def __getattr__(self, name):
        return getattr(self.sock, name)

def run_server(port):
    server = socket.socket()
    server.bind(('', port))
    server.listen(5)

    while True:
        csock, addr = server.accept()
        csock = ConnectedSocket(csock, addr)
        print("Accepted from {}".format(addr))

        while True:
            time.sleep(.5)
            try:
                csock.send(b'Hello')
            except socket.error as err:
                print("Error {} sending to peer {}".format(err, csock.get_peer()))
                csock.close()
                break

run_server(9999)