gpt4 book ai didi

python - 使用 python asyncio.create_server 实例提示用户输入

转载 作者:太空狗 更新时间:2023-10-29 17:07:40 25 4
gpt4 key购买 nike

我正在学习 python 3 asyncio 库,但遇到了一个小问题。我正在尝试调整 python 文档中的 EchoServer 示例以提示用户输入,而不仅仅是回显客户端发送的内容。

我认为这就像添加对 input() 的调用一样简单,但当然 input() 会阻塞,直到出现导致问题的用户输入。

理想情况下,即使服务器无话可说,我也希望继续从客户端接收数据。有点像聊天客户端,每个连接都在与服务器聊天。我希望能够在每个单独的连接之间切换,并根据需要从 stdin 发送输入。几乎就像一个 P2P 聊天客户端。

考虑以下修改后的 EchoServer 代码:

import asyncio

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

reply = input()
print('Send: {!r}'.format(reply))
self.transport.write(reply.encode())

#print('Close the client socket')
#self.transport.close()

loop = asyncio.get_event_loop()
# 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()

我如何在服务器端从标准输入获取输入并指定将其发送到哪个连接,同时仍然从连接的客户端接收输入?

最佳答案

您可以使用 loop.add_reader当数据在 sys.stdin 上可用时安排回调运行,然后使用 asyncio.Queue将接收到的标准输入数据传递给您的 data_received 方法:

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

唯一棘手的一点是我们如何调用 Queue.put/Queue.get 方法;它们都是协程,不能使用回调中的 yield fromProtocol 实例方法调用。相反,我们只是使用 asyncio.ensure_future 通过事件循环安排它们。 ,然后使用 add_done_callback 方法来处理我们从 get() 调用中检索到的回复。

注意:asyncio.ensure_future 是在 Python 3.4.4 中引入的。在此之前,该方法被称为 asyncio.async .此外,Python 3.7 引入了 asyncio.create_task ,这是现在的首选方法。

关于python - 使用 python asyncio.create_server 实例提示用户输入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29081929/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com