Python AsyncIO не может создать протокол из-за отсутствия транспорта, хотя транспорт присутствует - PullRequest
0 голосов
/ 26 мая 2018

Я пытаюсь написать прокси-сервер, используя AsyncIO asyncio.protocol, и это, кажется, работает по большей части.Но я получаю сообщение об ошибке, которое очень сильно смущает меня.

Мой код выглядит следующим образом:

import asyncio
import socket

users = {}

class UserConnection(object):
    def __init__(self, client_socket, proxy_socket, peername):
        self.client_socket = client_socket
        self.proxy_socket = proxy_socket
        self.peername = peername

class ClientProxyProtocol(asyncio.Protocol):
    def __init__(self):
        self.transport = None
        self.session = None
        server_connection = loop.create_connection(
                                lambda: ProxyForwardProtocol, 
                                host="127.0.0.1", 
                                port=25575)
        task = loop.create_task(server_connection)
        task.add_done_callback(self.handle_proxy_connection)

    def connection_made(self, transport):
        # Get peername, client socket and create proxy socket
        peername = transport.get_extra_info('peername')
        client_socket = transport.get_extra_info('socket')
        # Get session object for a user and add in dict keyed of proxy socket
        self.session = UserConnection(client_socket, None, peername)
        print('Connection from {}'.format(peername))
        self.transport = transport

    def handle_proxy_connection(self, task):
        trans, proto = task.result()
        proxy_socket = trans.get_extra_info("socket")
        self.session.proxy_socket = proxy_socket
        users[proxy_socket] = self.session
        print(trans,"\n",proto)

    def data_received(self, data):
        message = str(data) 
        print('Data received: {!r}'.format(message))

    def connection_lost(self, exc):        
        print('Close the client socket')
        self.transport.close()


class ProxyForwardProtocol(asyncio.Protocol):
    def __init__(self,transport):
        self.transport = transport

    def connection_made(self, transport):
        proxy_socket = transport.get_extra_info("socket")
        print("HELLO")
        self.transport = transport

    def connection_lost(self, exc):
        print("closing forward connection")
        self.transport.close()

loop = asyncio.get_event_loop()
# Each client connection will create a new protocol instance
coro = loop.create_server(ClientProxyProtocol, '127.0.0.1', 25565)
server = loop.run_until_complete(coro)

# Serve requests until Ctrl+C is pressed
print('Serving on {}'.format(server.sockets[0].getsockname()))
try:
    loop.run_forever()
except KeyboardInterrupt:
    pass

# Close the server
server.close()
loop.run_until_complete(server.wait_closed())
loop.close()

Запуск этого сценария в некоторой степени работает отлично, он принимает новые подключения и запускаетсяновый экземпляр протокола, но он выдает следующую ошибку после попытки установить соединение протокола с моим целевым сервером.Он выдает следующую ошибку:

Exception in callback ProxyForwardProtocol.connection_made(<_SelectorSoc...e, bufsize=0>>) at .\asyncproto.py:53        
handle: <Handle ProxyForwardProtocol.connection_made(<_SelectorSoc...e, bufsize=0>>) at .\asyncproto.py:53>             
Traceback (most recent call last):                                                                                        
File "C:\Users\Huhn\AppData\Local\Programs\Python\Python36-32\lib\asyncio\events.py", line 126, in _run                   
self._callback(*self._args)                                                                                         
TypeError: connection_made() missing 1 required positional argument: 'transport'

Мой вопрос следующий : дескриптор показывает, что метод connection_made принимает SelectorSocketTransport, который я бы принял за транспорт, но все ещеговорит, что отсутствует транспорт.Это не имеет смысла для меня.

Я был бы очень признателен, если бы кто-то мог сказать мне, в чем заключается моя ошибка, так как я не нашел никого с подобной проблемой и застрял.Если у меня есть какое-либо архитектурное неправильное представление о прокси, не стесняйтесь указывать на них.Я делаю это как учебное упражнение, поэтому я не использую сторонние альтернативы, которые могут там быть.

Спасибо

1 Ответ

0 голосов
/ 27 мая 2018

Кажется, вы только что сделали опечатку в ClientProxyProtocol.__init__().

В create_connection должен быть вызван первый аргумент, который возвращает объект протокола, вместо этого ваш (lambda: ProxyForwardProtocol) возвращает класс протокола .

Итак, когда платформа вызывает connection_made(), она передаст один аргумент (транспортный), но первый аргумент должен быть self.Протокол является классом, а не экземпляром класса -> метод connection_made() не связан -> self не предоставляется автоматически.

Удалите метод ProxyForwardProtocol.__init__ и измените свой вызов следующим образом:

    server_connection = loop.create_connection(
                            ProxyForwardProtocol, 
                            host="127.0.0.1", 
                            port=25575)
...