【问题标题】:Is there any way to getpeername() in Python after the socket disconnects?套接字断开连接后,有什么方法可以在 Python 中获取对等名称()?
【发布时间】:2018-12-09 18:50:09
【问题描述】:

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

#!/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 异常时,我的打印语句试图通过使用 connection.getpeername() 来确定哪个客户端断开连接,这不再有效。它抛出一个

socket.error: [Errno 107] Transport endpoint is not connected

异常。

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

一旦套接字断开连接,是否无法知道它之前连接到的端点? 为什么connection对象没有在connection.getpeername()中保留客户端的IP/端口信息, 即使在客户端断开连接后?这是因为connection 对象可能是可重用的吗?

我怎样才能让我的代码真正起作用,并打印出哪个客户端退出了?我是否需要将connection.getpeername() 的输出存储在一个变量中,以便稍后调用?这意味着如果我有多个 客户,我需要将每个客户的 connection.getpeername() 值存储在列表中吗?

我知道使用socket 是相当低级的,我很确定使用SocketServer.TCPServer 会更容易 - 我只是想了解所涉及的低级网络。

【问题讨论】:

    标签: python sockets networking


    【解决方案1】:

    不幸的是,这是操作系统界面的限制。在已知套接字已断开连接后,二进制 (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)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-04-27
      • 1970-01-01
      • 2020-04-19
      • 2016-10-02
      • 2020-01-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多