我有一个简单的streamreader,它正在侦听用于websocket实现的TCP端口。该流偶尔会读取(每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来观察端口,没有任何东西可以通过。我不正确地从港口读取,是否需要进行某种清理工作,或者读者偶尔会误读?我尝试过其他读取函数(读取和读取),偶尔会抛出类似的错误。
答案 0 :(得分:0)
readexactly()
是一种挑剔的方法。 From the documentation:
准确读取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