Как получить IP-адрес и порт вновь принятого соединения в Python asyncio server? - PullRequest
0 голосов
/ 03 февраля 2020

Я использую библиотеку asyncio в Python 3.8 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, но, возможно, другие могут указать мне правильное направление.

По классам транспорта Asyncio я вижу, что они позволяют вам запрашивать " дополнительная информация через функцию get_extra_info (str), например:

client_r._transport.get_extra_info('socket')

Хорошо, это работает для незашифрованных (не-SSL) трафиков c. Но я не могу запросить сокет на зашифрованном транспорте. Я могу получить только объект SSL:

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

Этот объект предоставляет атрибут «имя_сервера», который даст мне имя хоста / IP, который использовался для подключения, поэтому на данный момент мне просто нужен порт.

1 Ответ

0 голосов
/ 03 февраля 2020

Хорошо, я смог со временем разобраться.

Мне просто нужно было передать другой ключ в get_extra_info

И транспорты SSL и не-SSL поддерживают ключ "peername"

Поэтому я изменил свой код следующим образом:

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

Отдельная проблема, с которой я столкнулся, это то, что я запрашивал ключ 'peername' после закрытия потока, и так Я возвращал None.

...