【问题标题】:How do I get my asyncio client to call a socket server and waiting for response如何让我的异步客户端调用套接字服务器并等待响应
【发布时间】:2014-09-05 17:27:16
【问题描述】:

我正在使用asyncio.Protocol 服务器,其目的是让客户端调用服务器,但等待直到服务器响应并返回数据,然后再停止客户端循环。 p>

基于此处的异步文档 Echo 客户端和服务器: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) 也没有任何效果。

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

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

【问题讨论】:

  • 你想在从服务器得到应答后关闭客户端吗?还是别的什么?
  • 是的,我希望客户端和服务器之间的功能就像典型的同步方法调用一样,尽管是非阻塞的

标签: sockets client-server synchronous coroutine python-asyncio


【解决方案1】:

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

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()

【讨论】:

    【解决方案2】:

    您不必更改客户端代码。

    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,客户端将等待asyncio.sleep确定的2秒,然后停止。

    【讨论】:

      猜你喜欢
      • 2015-06-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多