我对Python asyncio和协议如何工作缺乏了解 .
看似相关的Documentaion:
class asyncio.Protocol
Protocol.eof_received()状态机显示相关转换AbstractEventLoop.run_until_complete(future)
echo tcp client的示例代码:
import asyncio
class EchoClientProtocol(asyncio.Protocol):
def __init__(self, message, loop):
self.message = message.encode()
def connection_made(self, transport):
self.transport = transport
self.write_data()
def data_received(self, data):
print('Data received: {!r}',len(data))
self.write_data()
def eof_received(self):
print("eof")
return True
def write_data(self):
print("write")
self.transport.write(self.message)
def connection_lost(self, exc):
print('The server closed the connection')
print('Stop the event loop')
loop = asyncio.get_event_loop()
message = 'Hello World!'
coro = loop.create_connection(lambda: EchoClientProtocol(message, loop),
'127.0.0.1', 5676)
loop.run_until_complete(coro)
print("done")
在echo服务器上同时输出:
write
Data received: {!r} 12
write
done
根据我的理解,这应该运行直到连接关闭 .
每次成功连接时,connect_made()和connection_lost()只调用一次 . 将在这两种方法之间调用所有其他回调,这样可以在协议实现中更轻松地进行资源管理 .
从状态机:
start
-> connection_made
[-> data_received]*
[-> eof_received]?
-> connection_lost
-> end
但是,函数 EchoClientProtocol.connection_lost
永远不会被调用, loop.run_until_complete(coro)
会在协议完成之前终止 .
问题是:
如何在协议的最终状态达到协议时以协程完成的方式获取协程/协议,并且loop.run_until_complete返回此类事件 .
2 回答
正如Sraw的回答所指出的那样,
loop.create_connection
是一个协程,它在创建传输/协议对后立即返回 . 所以你需要运行另一个协程(或等效对象)来保持事件循环活着,以便发生有趣的事情 .你没有正确地跟着你,你想要避免一个难看的
run_forever
,而是写下这样的东西:虽然
wait_connection_lost()
确实没有asyncio,但您提供协议实现,因此您可以轻松地为您的协议创建一个:loop.run_until_complete(coro)
返回transport, protocol
.因此,要触发
connection_lost
,连接应由服务器或客户端关闭 . 所以你需要:由于你没有在
connection_lost
中停止循环,它将永远被阻止 .BTW,
coro
在连接成功连接时返回 .