为什么这个 Python 3 asyncio 客户端只有在 Python 进程被中断后才发送字节?

3

为什么我的客户端在以下代码行超时:

response = yield from asyncio.wait_for(reader.read(), timeout=3.0)

而不是收到一条消息呢?

服务器只有在客户端超时并且我实际上发出ctrl + d以终止Python解释器后,才会注册来自此客户端的消息。


client.py

@asyncio.coroutine
def test_connection(host, port):
    # Get the streams for the socket
    print('Starting client connection')
    reader, writer = yield from asyncio.open_connection(host, port)

    message = 'Test Message'.encode('ascii')

    # Start communication
    print('Sending message to {}:{} - {}'.format(host, port, message))
    writer.write(message)

    print('Waiting 3 sec for response...')
    response = yield from asyncio.wait_for(reader.read(), timeout=3.0)
    print('Got response: {}'.format(response.decode('ascii')))

    writer.close()


def run():
    loop = asyncio.get_event_loop()
    task = asyncio.async(test_connection())
    loop.run_until_complete(task)
    loop.close()
1个回答

3
问题可能出在你在服务器端(也在客户端)调用了reader.read() ,这将会一直阻塞,直到从服务器发送一个EOF。但是,你很可能没有那样做——你只是发送一些字节并保持连接开放。
相反,你需要使用readline()并确保在你的消息有效载荷后添加b'\n',或者使用一些大小限制的read来限制等待的字节数,或者在写入消息有效载荷后调用writer.write_eof(),假设你不打算再使用writer。使用readline()write_eof 可能是最安全的选项。以下是一个完整的示例,演示如何使用readline():

client.py

import asyncio

@asyncio.coroutine
def test_connection(host, port):
    # Get the streams for the socket
    print('Starting client connection')
    reader, writer = yield from asyncio.open_connection(host, port)

    message = 'Test Message\n'.encode('ascii')

    # Start communication
    print('Sending message to {}:{} - {}'.format(host, port, message))
    writer.write(message)

    print('Waiting 3 sec for response...')
    response = yield from asyncio.wait_for(reader.readline(), timeout=5.0)
    print('Got response: {}'.format(response.decode('ascii')))

    writer.close()


def run():
    loop = asyncio.get_event_loop()
    task = asyncio.async(test_connection('localhost', 5000))
    loop.run_until_complete(task)
    loop.close()

run()

server.py

import asyncio

@asyncio.coroutine
def got_connection(reader, writer):
    msg = yield from reader.readline()
    message = 'another Test Message\n'.encode('ascii')
    print('Sending message to {}:{} - {}'.format('localhost', 5000, message))
    writer.write(message)


def run():
    loop = asyncio.get_event_loop()
    server = loop.run_until_complete(asyncio.start_server(
                                        got_connection, 'localhost', 5000))
    loop.run_until_complete(server.wait_closed())
    loop.close()

run()

这里是使用 write_eof() 的更改内容:

client.py

@asyncio.coroutine
def test_connection(host, port):
    # Get the streams for the socket
    print('Starting client connection')
    reader, writer = yield from asyncio.open_connection(host, port)

    message = 'Test Message'.encode('ascii')

    # Start communication
    print('Sending message to {}:{} - {}'.format(host, port, message))
    writer.write(message)
    writer.write_eof()

    print('Waiting 3 sec for response...')
    response = yield from asyncio.wait_for(reader.read(), timeout=5.0)
    print('Got response: {}'.format(response.decode('ascii')))

    writer.close()

server.py

@asyncio.coroutine
def got_connection(reader, writer):
    msg = yield from reader.read()
    message = 'another Test Message'.encode('ascii')
    print('Sending message to {}:{} - {}'.format('localhost', 5000, message))
    writer.write(message)
    writer.write_eof()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接