首页 文章

如何让我的asyncio客户端调用套接字服务器并等待响应

提问于
浏览
3

我正在使用 asyncio.Protocol 服务器,其目的是让客户端调用服务器,但 wait 直到服务器响应并在停止客户端循环之前返回数据 .

基于asyncio doc Echo Client和Server:https://docs.python.org/3/library/asyncio-protocol.html#protocol-example-tcp-echo-server-and-client,在调用时立即返回transport.write(...)的结果 .

通过经验,调用 loop.run_until_complete(coroutine) 失败 RuntimeError: Event loop is running.

在服务器的 data_received() 方法中运行 asyncio.sleep(n) 也没有任何效果 .

yield from asyncio.sleep(n) 中的 yield from asyncio.sleep(n)yield from asyncio.async(asyncio.sleep(n)) 都挂起服务器 .

我的问题是,如何让我的客户端在返回控制权之前等待服务器编写响应?

2 回答

  • 3

    我想永远不要直接使用传输/协议对 .

    asyncio具有用于高级编程的Streams API .

    客户端代码可能如下所示:

    @asyncio.coroutine
    def communicate():
        reader, writer = yield from asyncio.open_connection(HOST, PORT)
        writer.write(b'data')
        yield from writer.drain()
        answer = yield from reader.read()
        # process answer, maybe send new data back to server and wait for answer again
        writer.close()
    
  • 3

    您不必更改客户端代码 .

    echo-client.py

    #!/usr/bin/env python3.4
    import asyncio
    
    class EchoClient(asyncio.Protocol):
        message = 'Client Echo'
    
        def connection_made(self, transport):
            transport.write(self.message.encode())
            print('data sent: {}'.format(self.message))
    
        def data_received(self, data):
            print('data received: {}'.format(data.decode()))
    
        def connection_lost(self, exc):
            print('server closed the connection')
            asyncio.get_event_loop().stop()
    
    loop = asyncio.get_event_loop()
    coro = loop.create_connection(EchoClient, '127.0.0.1', 8888)
    loop.run_until_complete(coro)
    loop.run_forever()
    loop.close()
    

    诀窍是将代码(包括self.transport方法)放入协程并使用 wait_for() 方法,在需要返回值的语句前面加上 yield from 语句,或者需要一段时间才能完成的语句:

    echo-server.py

    #!/usr/bin/env python3.4
    import asyncio
    
    class EchoServer(asyncio.Protocol):
        def connection_made(self, transport):
            peername = transport.get_extra_info('peername')
            print('connection from {}'.format(peername))
            self.transport = transport
    
        def data_received(self, data):
            print('data received: {}'.format(data.decode()))
            fut = asyncio.async(self.sleeper())
            result = asyncio.wait_for(fut, 60)
    
        @asyncio.coroutine
        def sleeper(self):
            yield from asyncio.sleep(2)
            self.transport.write("Hello World".encode())
            self.transport.close()
    
    loop = asyncio.get_event_loop()
    coro = loop.create_server(EchoServer, '127.0.0.1', 8888)
    server = loop.run_until_complete(coro)
    print('serving on {}'.format(server.sockets[0].getsockname()))
    
    try:
        loop.run_forever()
    except KeyboardInterrupt:
        print("exit")
    finally:
        server.close()
        loop.close()
    

    调用 echo-server.py 然后 echo-client.py ,客户端将等待2秒,由 asyncio.sleep 确定,然后停止 .

相关问题