我有一个简单的流读取器,它正在监听 TCP 端口以实现 Websocket。该流偶尔会读取(每 30-300 秒)空白数据并引发错误。
loop = asyncio.get_event_loop()
coro = asyncio.start_server(handle_echo, 'not.real.ip.address', 8888, loop=loop)
server = loop.run_until_complete(coro)
server.close()
loop.run_until_complete(server.wait_closed())
loop.close()
@asyncio.coroutine
def handle_echo(reader, writer):
#Starts the connection with upgrade handshake
while True:
#read frame data
first_byte = yield from reader.readexactly(1)
opcode = first_byte & 0xf
second_byte = yield from reader.readexactly(1)
second_byte = ord(second_byte)
mask = second_byte >> 7
len1 = second_byte & 0x7f
if len1 == 126:
len2 = yield from reader.readexactly(2)
length = int.from_bytes(len2, byteorder='big')
elif len1 == 127:
len2 = yield from reader.readexactly(8)
length = int.from_bytes(len2, byteorder='big')
else:
length = len1
if mask:
masking_key = yield from reader.readexactly(4)
if length:
payload = yield from reader.readexactly(length)
payload = bytearray(payload)
if mask:
for i,b in enumerate(payload):
payload[i] = payload[i] ^ masking_key[i%4]
if opcode & 0x1:
payload = payload.decode("UTF-8")
每隔一段时间,就会抛出以下错误:
Future/Task exception was never retrieved
future: Task(<handle_echo>)<exception=IncompleteReadError('0 bytes read on a total of 1 expected bytes',)>
Traceback (most recent call last):
File "/usr/lib/python3.4/asyncio/tasks.py", line 300, in _step
result = coro.send(value)
File "server.py", line 76, in handle_echo
first_byte = yield from reader.readexactly(1)
File "/usr/lib/python3.4/asyncio/streams.py", line 464, in readexactly
raise IncompleteReadError(partial, len(partial) + n)
asyncio.streams.IncompleteReadError: 0 bytes read on a total of 1 expected bytes
我很难找出造成这种情况的原因。我已经使用 tcptrack 来监视端口,但什么也没有通过。我是否不正确地从端口读取数据,是否需要进行某种清理,或者读者偶尔会误读?我尝试过其他读取函数(read 和 readline),它们偶尔会抛出类似的错误。
readexactly()
是一种挑剔的方法。 来自文档:
准确读取 n 个字节。如果在读取 n 之前到达流末尾,则引发
,异常的IncompleteReadError
属性包含部分读取的字节。IncompleteReadError.partial
由于服务器有时似乎会发送空字节字符串,因此将
readexactly()
调用放在 try / except 块上可能是个好主意:
try:
first_byte = yield from reader.readexactly(1)
except asyncio.IncompleteReadError:
pass
else:
# Rest of your code
您甚至可以检查是否收到了超过 0(零)字节并缓冲它们(如果您的用例需要):
except asyncio.IncompleteReadError as e:
if len(e.partial) > 0:
# Handle the bytes read
else:
pass