【发布时间】:2018-12-27 20:09:37
【问题描述】:
下面是一个简单的回显服务器。但是如果客户端在 10 秒内没有发送任何东西,我想关闭连接。
import asyncio
async def process(reader: asyncio.StreamReader, writer: asyncio.StreamWriter):
print("awaiting for data")
line = await reader.readline()
print(f"received {line}")
writer.write(line)
print(f"sent {line}")
await writer.drain()
print(f"Drained")
async def timeout(task: asyncio.Task, duration):
print("timeout started")
await asyncio.sleep(duration)
print("client unresponsive, cancelling")
task.cancel()
print("task cancelled")
async def new_session(reader, writer):
print("new session started")
task = asyncio.create_task(process(reader, writer))
timer = asyncio.create_task(timeout(task, 10))
await task
print("task complete")
timer.cancel()
print("timer cancelled")
writer.close()
print("writer closed")
async def a_main():
server = await asyncio.start_server(new_session, port=8088)
await server.serve_forever()
if __name__ == '__main__':
asyncio.run(a_main())
如果客户端发送消息,它工作正常。但是另一种情况,当客户端保持沉默时,它不起作用
客户端发送消息时:
new session started
awaiting for data
timeout started
received b'slkdfjsdlkfj\r\n'
sent b'slkdfjsdlkfj\r\n'
Drained
task complete
timer cancelled
writer closed
当客户端打开连接后静默时
new session started
awaiting for data
timeout started
client unresponsive, cancelling
task cancelled
没有task complete、timer cancelled、writer closed。
上面的代码有什么问题?- 有没有更好的方法来实现超时?
更新
找出问题所在,看起来任务实际上被取消了,但是异常被静默忽略了,通过捕获CancelledError修复了问题
async def new_session(reader, writer):
print("new session started")
task = asyncio.create_task(process(reader, writer))
timer = asyncio.create_task(timeout(task, 10))
try:
await task
except asyncio.CancelledError:
print(f"Task took too long and was cancelled by timer")
print("task complete")
timer.cancel()
print("timer cancelled")
writer.close()
print("writer closed")
第二部分仍然存在。有没有更好的方法来实现超时?
更新2
使用wait_for 完成代码。不再需要超时代码。在下面检查接受的solution:
async def new_session(reader, writer):
print("new session started")
try:
await asyncio.wait_for(process(reader, writer), timeout=5)
except asyncio.TimeoutError as te:
print(f'time is up!{te}')
finally:
writer.close()
print("writer closed")
【问题讨论】:
-
你可以用
asyncio.wait_for代替timeout。 -
@user4815162342 谢谢。您想将其添加为答案吗?我会接受的。
标签: python python-3.x python-asyncio session-timeout