Why is this Python 3 asyncio client sending the bytes only after the Python process is interrupted?

时间:2015-05-04 19:48:48

标签: python client-server python-3.4 python-asyncio

Why is my client timing out at code line:

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

instead of getting a message back?

The server piece only registers it got a message from this client after the client times out and I actually issue a ctrl + d to kill the Python interpreter


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

答案 0 :(得分: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()