Prompt for user input using python asyncio.create_server instance

后端 未结 1 1466
忘了有多久
忘了有多久 2020-12-13 20:01

I\'m learning about python 3 asyncio library, and I\'ve run into a small issue. I\'m trying to adapt the EchoServer example from the python docs to prompt for user input rat

相关标签:
1条回答
  • 2020-12-13 20:29

    You can use loop.add_reader schedule a callback to run when data is available on sys.stdin, and then use an asyncio.Queue to pass the stdin data received to your data_received method:

    import sys
    import asyncio
    
    
    def got_stdin_data(q):
        asyncio.ensure_future(q.put(sys.stdin.readline()))
    
    class EchoServerClientProtocol(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):
           message = data.decode()
           print('Data received: {!r}'.format(message))
           fut = asyncio.ensure_future(q.get())
           fut.add_done_callback(self.write_reply)
    
       def write_reply(self, fut):
           reply = fut.result()
           print('Send: {!r}'.format(reply))
           self.transport.write(reply.encode())
    
           #print('Close the client socket')
           #self.transport.close()
    
    q = asyncio.Queue()
    loop = asyncio.get_event_loop()
    loop.add_reader(sys.stdin, got_stdin_data, q)
    # Each client connection will create a new protocol instance
    coro = loop.create_server(EchoServerClientProtocol, '127.0.0.1', 8888)
    server = loop.run_until_complete(coro)
    
    # Serve requests until CTRL+c is pressed
    print('Serving on {}'.format(server.sockets[0].getsockname()))
    try:
        loop.run_forever()
    except KeyboardInterrupt:
        pass
    
    # Close the server
    server.close()
    loop.run_until_complete(server.wait_closed())
    loop.close()
    

    The only tricky bit is how we call the Queue.put/Queue.get methods; both of them are coroutines, which can't be called using yield from in the callback or the Protocol instance methods. Instead, we just schedule them with the event loop using asyncio.ensure_future, and then use the add_done_callback method to handle the reply we retrieve from the get() call.

    Note: asyncio.ensure_future was introduced in Python 3.4.4. Prior to that, the method was called asyncio.async. Additionally, Python 3.7 introduced asyncio.create_task, which is now the preferred method.

    0 讨论(0)
提交回复
热议问题