Asyncio StreamReader偶尔会读取0个字节

时间:2015-02-17 05:43:54

标签: python-3.x python-asyncio

我有一个简单的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来观察端口,没有任何东西可以通过。我不正确地从港口读取,是否需要进行某种清理工作,或者读者偶尔会误读?我尝试过其他读取函数(读取和读取),偶尔会抛出类似的错误。

1 个答案:

答案 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