Python asyncio tcp套接字:当套接字关闭时,如何取消asyncio.sleep()?

Python asyncio tcp套接字:当套接字关闭时,如何取消asyncio.sleep()?,python,sockets,python-asyncio,Python,Sockets,Python Asyncio,我目前正在实现TCP套接字协议。该协议要求每五分钟发送一次心跳消息。我正在Python中使用asyncio实现一个协议。下面的源代码是一个程序,它连接到localhost:8889,发送hello,并在1秒后断开套接字连接。在这种情况下,连接会在一秒钟后断开(如果确实发生这种情况,则表示网络已关闭或服务器已断开)。问题是send_heartbeat函数在不知道套接字已关闭的情况下等待5分钟。我想立即取消协同程序,而不是在插座断开时等待5分钟。最好的方法是什么 导入异步IO 异步def运行(主机:

我目前正在实现TCP套接字协议。该协议要求每五分钟发送一次心跳消息。我正在Python中使用asyncio实现一个协议。下面的源代码是一个程序,它连接到localhost:8889,发送hello,并在1秒后断开套接字连接。在这种情况下,连接会在一秒钟后断开(如果确实发生这种情况,则表示网络已关闭或服务器已断开)。问题是send_heartbeat函数在不知道套接字已关闭的情况下等待5分钟。我想立即取消协同程序,而不是在插座断开时等待5分钟。最好的方法是什么

导入异步IO
异步def运行(主机:str,端口:int):
尽管如此:
尝试:
读写器=等待异步IO。打开\u连接(主机、端口)
除O错误为e外:
打印('连接失败:',e)
等待异步睡眠(0.5)
持续
等待异步IO([
处理流(读卡器、写卡器),
发送心跳信号(读写器),
],返回_when=asyncio.FIRST_COMPLETED)#将在1秒后停止
writer.close()#1秒后关闭套接字
等待编写器。等待关闭()
异步def句柄\u流(读写器):
writer.write(b'hello\n')#将成功,因为套接字处于活动状态
等待writer.drain()
等待asyncio.sleep(1)
异步def发送\u心跳(读写器):
尽管如此:
等待异步睡眠(300)
heartbeat\u message=b'heartbeat\n'
writer.write(心跳消息)将失败,因为套接字在1秒后已关闭
等待writer.drain()
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
asyncio.run(run('127.0.0.1',8889))

您可以通过取消执行睡眠的任务来取消睡眠。将
send_heartbeat
创建为一个单独的任务,可确保它在等待后者时与
handle_stream
并行运行:

async def run(host: str, port: int):
    while True:
        ...
        heartbeat = asyncio.create_task(send_heartbeat(reader, writer))
        try:
            await handle_stream(reader, writer)
        finally:
            heartbeat.cancel()
            writer.close()
        await writer.wait_closed()

顺便说一句,由于您正在等待
writer.drain()
中的
handle\u stream
,因此不能保证
handle\u stream
总是在1秒内完成。这可能是一个您可能希望避免流失的地方,或者您可以在等待
处理流(…)
时使用它,您可以通过取消执行它的任务来取消睡眠。将
send_heartbeat
创建为一个单独的任务,可确保它在等待后者时与
handle_stream
并行运行:

async def run(host: str, port: int):
    while True:
        ...
        heartbeat = asyncio.create_task(send_heartbeat(reader, writer))
        try:
            await handle_stream(reader, writer)
        finally:
            heartbeat.cancel()
            writer.close()
        await writer.wait_closed()

顺便说一句,由于您正在等待
writer.drain()
中的
handle\u stream
,因此不能保证
handle\u stream
总是在1秒内完成。这可能是一个您可能希望避免排放的地方,或者您可以在等待
handle\u流时使用(…)

您可以从send_心跳创建一个任务,并每n秒轮询一次,如果完成了,则继续。如果您检查套接字及其关闭状态,则可以取消并中断循环。您可以从send_心跳创建一个任务,并每n秒轮询一次,如果完成了,则继续检查套接字并关闭后,您可以取消并中断循环调用
send\u heartbeat
create\u task
看起来比我的代码更直观、更简洁。非常感谢。使用
create\u task
调用
send\u heartbeat
,看起来比我的代码更直观、更简洁。非常感谢。