为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Qyouu 2021-09-11 18:27:34
我有一个像这样的简单服务器:#!/usr/bin/env python2import socketserver = socket.socket(socket.AF_INET, socket.SOCK_STREAM)server.bind(('localhost', 50000))server.listen(5)# Set TCP Keepaliveserver.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对象也不保留客户端的 IP/端口信息connection.getpeername()?这是因为该connection对象可能是可重用的吗?我怎样才能让我的代码真正工作,并打印出哪个客户端退出了?我是否需要将 的输出存储connection.getpeername()在一个变量中,以便我以后可以调用它?这意味着如果我有多个客户端,我需要将connection.getpeername()每个客户端的值存储在列表中吗?我知道使用socket是相当低级的,而且我很确定实际使用SocketServer.TCPServer会更容易 - 我只是想了解所涉及的低级网络。
查看完整描述

1 回答

?
阿波罗的战车

TA贡献1862条经验 获得超6个赞

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


查看完整回答
反对 回复 2021-09-11
  • 1 回答
  • 0 关注
  • 190 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信