看不到 `asyncio.Transport.write()` 的任何效果
Can't see any effect of `asyncio.Transport.write()`
我正在尝试使用 asyncio 制作一个简单的自制本地主机 TCP 服务器(它只有 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 文档中的 echo 服务器示例中的所有内容,但显然 data_received()
中的 write()
和 close()
没有好像没什么效果。
我错过了什么?
据我所知,您的代码唯一的问题是您没有发出正确的 HTTP 响应,而只是发出字符串 "Hi"。例如,运行 您的代码未更改并将其连接到 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。
我正在尝试使用 asyncio 制作一个简单的自制本地主机 TCP 服务器(它只有 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 文档中的 echo 服务器示例中的所有内容,但显然 data_received()
中的 write()
和 close()
没有好像没什么效果。
我错过了什么?
据我所知,您的代码唯一的问题是您没有发出正确的 HTTP 响应,而只是发出字符串 "Hi"。例如,运行 您的代码未更改并将其连接到 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。