Python 3.x Asyncios正在等待reader。read()将永远等待

Python 3.x Asyncios正在等待reader。read()将永远等待,python-3.x,sockets,python-asyncio,Python 3.x,Sockets,Python Asyncio,我有一个这样写的小型服务器: async def handle_client(reader, writer): request = (await reader.read()).decode('utf8') # should read until end of msg print(request) response = "thx" writer.write(response.encode('utf8')) await writer.dra

我有一个这样写的小型服务器:

async def handle_client(reader, writer):
    request = (await reader.read()).decode('utf8') # should read until end of msg
    print(request)
    response = "thx"
    writer.write(response.encode('utf8'))
    await writer.drain()
    writer.close()


loop = asyncio.get_event_loop()
loop.create_task(asyncio.start_server(handle_client, socket.gethostname(), 8886))
loop.run_forever()
async def tcp_echo_client(message):
    reader, writer = await asyncio.open_connection(
        my_ip, 8886)

    print(f'Send: {message!r}')
    writer.write(message.encode())
    await writer.drain()
    data = await reader.read() # should read until end of msg
    print(f'Received: {data.decode()!r}')
    print('Close the connection')
    writer.close()
    await writer.wait_closed()

asyncio.run(tcp_echo_client(f"Hello World!"))
    while True:
        request = (await reader.read(1024)).decode('utf8')
        if not request:
            break
一个小客户这样写:

async def handle_client(reader, writer):
    request = (await reader.read()).decode('utf8') # should read until end of msg
    print(request)
    response = "thx"
    writer.write(response.encode('utf8'))
    await writer.drain()
    writer.close()


loop = asyncio.get_event_loop()
loop.create_task(asyncio.start_server(handle_client, socket.gethostname(), 8886))
loop.run_forever()
async def tcp_echo_client(message):
    reader, writer = await asyncio.open_connection(
        my_ip, 8886)

    print(f'Send: {message!r}')
    writer.write(message.encode())
    await writer.drain()
    data = await reader.read() # should read until end of msg
    print(f'Received: {data.decode()!r}')
    print('Close the connection')
    writer.close()
    await writer.wait_closed()

asyncio.run(tcp_echo_client(f"Hello World!"))
    while True:
        request = (await reader.read(1024)).decode('utf8')
        if not request:
            break
客户端和服务器启动通信,但从未完成通信。 为什么读者不能识别msg的结尾

如果我写

request = (await reader.read(1024)).decode('utf8')
相反,它可以工作,但我需要接收未定义的大量数据

我试图修改服务器的代码,如下所示:

async def handle_client(reader, writer):
    request = (await reader.read()).decode('utf8') # should read until end of msg
    print(request)
    response = "thx"
    writer.write(response.encode('utf8'))
    await writer.drain()
    writer.close()


loop = asyncio.get_event_loop()
loop.create_task(asyncio.start_server(handle_client, socket.gethostname(), 8886))
loop.run_forever()
async def tcp_echo_client(message):
    reader, writer = await asyncio.open_connection(
        my_ip, 8886)

    print(f'Send: {message!r}')
    writer.write(message.encode())
    await writer.drain()
    data = await reader.read() # should read until end of msg
    print(f'Received: {data.decode()!r}')
    print('Close the connection')
    writer.close()
    await writer.wait_closed()

asyncio.run(tcp_echo_client(f"Hello World!"))
    while True:
        request = (await reader.read(1024)).decode('utf8')
        if not request:
            break
它接收所有数据块,但在最后一个数据块之后仍然永远等待。为什么?
如何让服务器上的读卡器停止侦听并在代码中继续发送答案?

TCP连接是基于流的,这意味着当您将“消息”写入套接字时,字节将发送到对等方,而不在消息之间包含分隔符。连接另一端的对等方可以检索字节,但它需要自己弄清楚如何将它们分割成“消息”。这就是读取最后一个块时出现挂起的原因:
read()
只是等待对等方发送更多数据

为了能够检索单个消息,发送者必须对每个消息进行框架或分隔。例如,发送方可以在发送消息后关闭连接,这将允许另一方读取消息,因为它后面会有文件结束指示符。然而,这将允许发送者只发送一条消息,而不能读取响应,因为套接字将被关闭

更好的选择是写入程序只关闭套接字的写入端,这种部分关闭有时被称为“关闭”)。在asyncio中,这是通过调用:

这样发送,消息后面会有文件结尾,服务器端的读取不会挂起。虽然客户端将能够读取响应,但它仍将被限制为仅发送一条消息,因为在写入端已关闭的套接字上无法进行进一步写入

要实现由任意数量的请求和响应组成的通信,需要对每条消息进行帧处理。一种简单的方法是在每条消息前面加上消息长度:

writer.write(struct.pack('<L', len(request)))
writer.write(request)

writer.write(struct.pack(“TCP连接是基于流的,这意味着当您将“消息”写入套接字时,字节将被发送到对等方,而消息之间不包含分隔符。连接另一端的对等方可以检索字节,但它需要自己弄清楚如何将它们分割为“消息”。这就是读取最后一个块时出现挂起的原因:
read()
只是等待对等方发送更多数据

若要启用对单个邮件的检索,发件人必须对每条邮件进行框架或分隔。例如,发件人可以在发送邮件后关闭连接,这将允许另一方读取邮件,因为后面会有文件结尾指示符。但是,这将允许发件人只发送一封带有无法读取响应,因为套接字将被关闭

更好的选择是写入程序只关闭套接字的写入端,这种部分关闭有时被称为)。在asyncio中,这是通过调用:

以这种方式发送消息时,消息后面会有文件结尾,服务器端的读取不会挂起。虽然客户端可以读取响应,但仍将限于只发送一条消息,因为在写入端已关闭的套接字上无法进一步写入

要实现由任意数量的请求和响应组成的通信,您需要对每条消息设置帧。一种简单的方法是在每条消息前面加上消息长度:

writer.write(struct.pack('<L', len(request)))
writer.write(request)

writer.write(struct.pack('非常感谢!!
writer.write\u eof()
完成了工作。非常感谢!!
writer.write\u eof()
完成了工作。