【问题标题】:How to get IP address and port of newly accepted connection in Python asyncio server?如何在 Python asyncio 服务器中获取新接受的连接的 IP 地址和端口?
【发布时间】:2020-02-03 16:23:20
【问题描述】:

我在 Python 3.8 中使用 asyncio 库 https://docs.python.org/3/library/asyncio.html

我正在创建一个服务器,在“新接受的连接”回调函数中,我想找出新客户端的远程IP地址和端口。

回调函数的参数是用于从客户端读取和写入的 StreamReader 和 StreamWriter 各自的一个实例。有没有一种直接的方法可以找到流的 IP 地址和端口?请注意,我想对 SSL 和非 SSL 连接都这样做。

我在这里创建服务器:

async def create_server(self, new_client_cb, host, port):
    srvsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    srvsocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    srvsocket.bind((host, port))
    srvsocket.listen(5)
    return await asyncio.start_server(new_client_cb, sock=srvsocket, start_serving=False)

我传入回调函数,它遵循文档并接受 StreamReader 和 StreamWriter 的实例。

这里说的是回调函数。它是类的一部分,因此是主要的 self 论点。

async def _new_client(self, client_r, client_w):
    try:
        self.logger.debug("New client on incoming proxy")
        dests_r = {}
        dests_w = {}
        for addr in self.config['addrlist']:
            host, port = addr.split(':')
            host = socket.gethostbyname(host)
            self.logger.debug(f"Connecting to {addr}...")
            r, w = await self.protocol.open_connection(host, port)
            self.logger.debug(f"Connected to {addr}")
            dests_r[addr] = r
            dests_w[addr] = w
        done, pending = await asyncio.wait(
            [self._tunnel(list(dests_r.values()), [client_w]), self._tunnel([client_r], list(dests_w.values()))],
            return_when=asyncio.FIRST_EXCEPTION
        )
        for result in done:
            if result.exception():
                raise result.exception()
    except Exception as e:
        self.logger.error(f"Caught exception: {str(e)}")
        traceback.print_exc()

该功能有很多与我的其他方面相关的内容 应用。 我认为我的问题最终归结为:在给定这些输入 StreamReader 和 StreamWriter 的情况下,我如何找到与新客户端关联的远程地址和端口?我正在研究 asyncio 的传输类:https://docs.python.org/3/library/asyncio-protocol.html 但也许其他人可以为我指明正确的方向。

Wrt asyncio 的 Transport 类,我可以看到它们允许您通过 get_extra_info(str) 函数查询“额外”信息,例如:

client_r._transport.get_extra_info('socket')

好的,这适用于非加密(非 SSL)流量。但我无法在加密传输中查询套接字。我只能获取 SSL 对象:

https://docs.python.org/3/library/ssl.html#ssl.SSLObject

这个对象提供了一个属性“server_hostname”,它将给我用于连接的主机名/IP,所以此时我只需要端口。

【问题讨论】:

  • 如果你也发布你所做的事情(你的代码)会有所帮助。如果您实际显示它,则更容易理解您所说的回调函数。

标签: python python-asyncio


【解决方案1】:

好吧,我终于弄明白了。

我真的只需要向 get_extra_info 传递一个不同的密钥

SSL 和非 SSL 传输都支持“peername”密钥

所以我修改了我的代码如下:

client_r._transport.get_extra_info('peername')
client_w._transport.get_extra_info('peername')

我遇到的另一个问题是我在 Stream 关​​闭后查询 'peername' 键,所以我没有返回。

【讨论】:

  • 您应该致电client_w.get_extra_info('peername')。流上的_transport 属性是私有的,可以随时删除或重命名(或更改含义)。 Example 在文档中。
  • 你说得有道理。但是,我也想从 StreamReaders 中读取 peername,它没有像 StreamWriters 那样提供 get_extra_info 方法。坦率地说,我认为这是 API 的疏忽。
  • 读写器同时交;我想你可以从作者那里提取 peername 并将其传递给需要它的代码。
猜你喜欢
  • 2011-10-03
  • 1970-01-01
  • 2014-05-26
  • 1970-01-01
  • 1970-01-01
  • 2021-12-10
  • 1970-01-01
  • 1970-01-01
  • 2019-02-24
相关资源
最近更新 更多