【问题标题】:How to implement timeout in asyncio server?如何在异步服务器中实现超时?
【发布时间】: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 completetimer cancelledwriter closed

  1. 上面的代码有什么问题?
  2. 有没有更好的方法来实现超时?

更新

找出问题所在,看起来任务实际上被取消了,但是异常被静默忽略了,通过捕获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


【解决方案1】:

我在建立连接时使用以下代码。我建议对您的代码同样使用 wait_for。

fut = asyncio.open_connection( self.host, self.port, loop=self.loop )
try:
   r, w = await asyncio.wait_for(fut, timeout=self.connection_timeout)
except asyncio.TimeoutError:
   pass

【讨论】:

  • open_connection 当您是客户时。问题是针对服务器的。
  • 这是一个如何使用 wait_for 的示例,这是您想要做的pythonic解决方案。
  • 我没有意识到它可以用于任何等待。赞成。
【解决方案2】:

有没有更好的方法来实现超时?

您可以使用asyncio.wait_for 代替timeout。它具有相似的语义,但已经带有 asyncio。此外,您可以等待它返回的 future 以检测是否发生超时。

【讨论】:

    猜你喜欢
    • 2016-11-18
    • 1970-01-01
    • 2012-07-16
    • 2013-09-09
    • 2010-12-25
    • 2014-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多