当客户端发送大消息〜5300字节时,asyncio获得2917-2923字节,然后引发此错误.Python 3.7。 未收到的邮件最终结束
{“ item”:4,“ active”:false,“ num”:2,“ turn_touch”:0,“ damaged_in_turn”:0},{“ item”:7,“ active”:fal
当然,json无法解析此消息
错误日志
ERROR:asyncio:Fatal error: protocol.data_received() call failed.
protocol: <__main__.Server object at 0xb5a2e0ac>
transport: <_SelectorSocketTransport fd=9 read=polling write=<idle, bufsize=0>>
Traceback (most recent call last):
File "/usr/lib/python3.7/asyncio/selector_events.py", line 824, in _read_ready__data_received
self._protocol.data_received(data)
File "/home/den/piratebay/server.py", line 41, in data_received
self.message_handle.check_message_id(self, data)
File "/home/den/piratebay/message_handle.py", line 25, in check_message_id
self.parsed_data = parse_data(data)
File "/home/den/piratebay/action.py", line 50, in parse_data
return json.loads(data)
File "/usr/lib/python3.7/json/__init__.py", line 348, in loads
return _default_decoder.decode(s)
File "/usr/lib/python3.7/json/decoder.py", line 337, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "/usr/lib/python3.7/json/decoder.py", line 355, in raw_decode
raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 2918 (char 2917)
server.py
class Server(asyncio.Protocol):
def connection_made(self, transport):
logging.debug('connection_made')
""" Called on instantiation, when new client connects """
self.transport = transport
self.addr = transport.get_extra_info('peername')
s = transport.get_extra_info("socket")
print('Connection from {}'.format(self.addr))
def data_received(self, data):
""" Handle data as it's received. """
logging.debug('received {} bytes'.format(len(data)))
data = data.decode()
print('received data->',data)
self.message_handle.check_message_id(self, data)
def connection_lost(self, ex):
""" Called on client disconnect. Clean up client state """
self.transport.close()
if __name__ == '__main__':
loop = asyncio.get_event_loop()
# Create server and initialize on the event loop
coroutine = loop.create_server(Server,
host=HOST,
port=PORT)
此错误的原因是什么?谢谢!
答案 0 :(得分:1)
不能保证单个data_received
会收到整个应用程序级消息。 TCP是基于流的协议,甚至不提供 message 的概念,而只是提供字节流。客户端上的一次写入可以分为多个数据包,并由服务器进行多次读取。相反,可以将多个写入合并为一个数据包并作为一个单元接收。
正确编写的asyncio程序不能假设所有数据都将在单个data_received
调用中到达。相反,data_received
必须收集传入的数据,识别数据何时完成,然后才处理数据。如何识别消息的结尾将取决于所使用的协议-例如,http提供了预先声明内容长度的选项。如果希望客户端在发送消息后断开连接,则遇到文件结束条件将识别出消息的结束。
在后一种情况下,data_received
将收集字节,这些字节将由eof_received
处理:
import asyncio, io
class Server(asyncio.Protocol):
def connection_made(self, transport):
self.transport = transport
addr = transport.get_extra_info('peername')
print('Connection from {}'.format(addr))
self._data = io.BytesIO()
def data_received(self, data):
print('received data->',data)
self._data.write(data)
def eof_received(self):
print('received EOF')
self._data.write(data)
data = self._data.getvalue()
data = data.decode()
self.message_handle.check_message_id(self, data)
def connection_lost(self, ex):
self.transport.close()
请注意,上述代码使用基于流的API编写起来要简单得多,这是编写现代异步代码的recommended方法:
import asyncio
async def handle_client(r, w):
data = await r.read() # read until EOF
data = data.decode()
message_handle.check_message_id(data)
# ...
loop = asyncio.get_event_loop()
message_handle = ...
server = loop.run_until_complete(
asyncio.start_server(
lambda r, w: handle_client(r, w, message_handle),
'127.0.0.1', 8888))
loop.run_forever()