这是使用
asyncio streams(适用于Unix)将标准输入
stdin
回显到标准输出
stdout
的示例。
import asyncio
import sys
async def connect_stdin_stdout():
loop = asyncio.get_event_loop()
reader = asyncio.StreamReader()
protocol = asyncio.StreamReaderProtocol(reader)
await loop.connect_read_pipe(lambda: protocol, sys.stdin)
w_transport, w_protocol = await loop.connect_write_pipe(asyncio.streams.FlowControlMixin, sys.stdout)
writer = asyncio.StreamWriter(w_transport, w_protocol, reader, loop)
return reader, writer
async def main():
reader, writer = await connect_stdin_stdout()
while True:
res = await reader.read(100)
if not res:
break
writer.write(res)
await writer.drain()
if __name__ == "__main__":
asyncio.run(main())
作为一个即插即用的解决方案,你可以使用
aioconsole库。它实现了类似的方法,同时还提供了额外有用的异步等效函数来替代
input
、
print
、
exec
和
code.interact
。
from aioconsole import get_standard_streams
async def main():
reader, writer = await get_standard_streams()
更新:
让我们试着弄清楚函数connect_stdin_stdout
的工作原理。
- 获取当前的事件循环:
loop = asyncio.get_event_loop()
创建一个
StreamReader
实例。
reader = asyncio.StreamReader()
通常情况下,
StreamReader/StreamWriter
类不打算直接实例化,而应该只作为诸如
open_connection()
和
start_server()
等函数的结果使用。
StreamReader
提供了对某个数据流的缓冲异步接口。一些源代码(库代码)调用它的函数,例如
feed_data
、
feed_eof
,数据被缓冲起来,并可以使用
documented接口协程
read()
、
readline()
等进行读取。
- 创建
StreamReaderProtocol
实例。
protocol = asyncio.StreamReaderProtocol(reader)
这个类继承自
asyncio.Protocol
和
FlowControlMixin
,用于在
Protocol
和
StreamReader
之间进行适配。它重写了
Protocol
的
data_received
、
eof_received
等方法,并调用
StreamReader
的
feed_data
方法。
- 在事件循环中注册标准输入流
stdin
。
await loop.connect_read_pipe(lambda: protocol, sys.stdin)
connect_read_pipe
函数的pipe
参数是一个类似文件的对象。而stdin
就是一个类似文件的对象。从现在开始,所有从stdin
读取的数据都会进入StreamReaderProtocol
,然后传递给StreamReader
。
- 在事件循环中注册标准输出流
stdout
。
w_transport, w_protocol = await loop.connect_write_pipe(FlowControlMixin, sys.stdout)
在`connect_write_pipe`中,您需要传递一个协议工厂,该工厂创建实现`StreamWriter.drain()`流控逻辑的协议实例。这个逻辑是在`FlowControlMixin`类中实现的。同时,`StreamReaderProtocol`也继承自它。
6. 创建`StreamWriter`实例。
writer = asyncio.StreamWriter(w_transport, w_protocol, reader, loop)
这个类使用
write()
、
writelines()
等函数将传递给它的数据转发到底层的
transport
。
protocol
用于支持
drain()
函数,以等待底层传输刷新其内部缓冲区并再次可写入。
reader
是一个可选参数,可以是
None
,它也用于支持
drain()
函数,在该函数开始时检查读取器是否设置了异常,例如由于连接丢失(对套接字和双向连接相关),然后
drain()
也会抛出异常。
您可以在这个很棒的
答案中了解更多关于
StreamWriter
和
drain()
函数的信息。
更新2:
要使用
\r\n
分隔符读取行,可以使用
readuntil。
writer.write
и°ғз”Ёзҡ„ең°ж–№жҳҜдёҚжҳҜжү“й”ҷдәҶпјҹ - olioraawait drain()
时使用write
是正确的。我已经更新了答案。谢谢你的注意。 - alex_noname