Не вижу никакого эффекта от `asyncio.Transport.write ()` - PullRequest
0 голосов
/ 30 марта 2020

Я пытаюсь создать простой доморощенный локальный TCP-сервер, используя asyncio (это всего лишь Python 3.6.9, поскольку у меня только LTS Ubuntu на этой машине):

import asyncio
import socket
import urllib.parse
from http.server import BaseHTTPRequestHandler
from io import BytesIO

class HTTPRequest(BaseHTTPRequestHandler):
    def __init__(self, request_text):
        self.rfile = BytesIO(request_text)
        self.raw_requestline = self.rfile.readline()
        self.error_code = self.error_message = None
        self.parse_request()
        rpc_request = urllib.parse.urlparse(self.path)
        self.endpoint = rpc_request.path
        self.query = urllib.parse.parse_qs(rpc_request.query)

    def send_error(self, code, message):
        self.error_code = code
        self.error_message = message


class Srv(asyncio.Protocol):
    def __init__(self, address=('127.0.0.1', 12345), family=socket.AF_INET, loop: asyncio.AbstractEventLoop=None):
        self._address = address
        self._family = family
        self._loop = loop if loop is not None else asyncio.get_event_loop()
        self._server = None

    def connection_made(self, transport):
        self._transport = transport

    def data_received(self, data):
        request = HTTPRequest(data)
        print("\tQuery:", request.query)
        self._transport.write(b'Hi!')
        self._transport.close()

    def eof_received(self):
        pass

    def factory(self):
        return self

    async def run(self):
        sock = socket.socket(family=self._family)
        sock.bind(self._address)
        sock.listen()
        if self._family == socket.AF_UNIX:
            self._server = await self._loop.create_unix_server(protocol_factory=self.factory, sock=sock)
        else:
            self._server = await self._loop.create_server(protocol_factory=self.factory, sock=sock, family=self._family)
        self._running = True

omg = Srv()

async def wat():
    await omg.run()
    await omg._server.wait_closed()

try:
    asyncio.get_event_loop().run_until_complete(wat())
except:
    omg._server.close()

Кажется, запуск и даже получение данных:

$ python3 0_o.py 
    Query: {'data': ['"abcd"']}
    Query: {'data': ['"abcd"']}

(отпечатки сделаны с Srv.data_received), но curl говорит, что не получает от него ответа:

$ curl '127.0.0.1:12345/query?data="abcd"'
curl: (52) Empty reply from server
$ curl '127.0.0.1:12345/query?data="abcd"'
curl: (52) Empty reply from server

С моей точки зрения, я я переопределил все из примеров эхо-серверов в документации python stdlib, но, очевидно, write() и close() внутри data_received(), похоже, не дают никакого эффекта.

Чего мне не хватает?

1 Ответ

0 голосов
/ 30 марта 2020

Насколько я могу судить, единственная проблема в вашем коде состоит в том, что вы отправляете не правильный HTTP-ответ, а просто строку "Привет". Например, выполнение кода без изменений и его подключение с nc приводит к следующему:

$ nc localhost 12345
GET / HTTP/1.0
Hi!

Обратите внимание не только на отсутствие правильного ответа, но и на тот факт, что сервер даже не ждал клиент для завершения запроса. Вместо этого он немедленно распечатал неверно сформированный ответ.

Соединение с curl приводит к следующему выводу:

$ curl http://localhost:12345/
curl: (1) Received HTTP/0.9 when not allowed

«HTTP / 0,9» относится к древней версии HTTP протокол, в котором строка состояния была необязательной. Этот ответ отклоняется curl, но Wget примет его:

$ wget -qO- http://localhost:12345/
Hi!

Вместо того, чтобы пытаться реализовать HTTP вручную, вы можете заглянуть в библиотеку, которая делает это за вас, например, aiohttp .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...