如何在异步服务器中实现超时? - python

下面是一个简单的回显服务器。但是,如果客户端在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

  • 上面的代码有什么问题?
  • 是否有更好的方法来实现超时?
  • 更新

    找出问题,看起来任务实际上已取消,但是异常被忽略,通过捕获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。它具有类似的语义,但是已经带有asyncio。另外,您可以等待将来返回以检测是否发生了超时。

    Python:检查是否存在维基百科文章 - python

    我试图弄清楚如何检查Wikipedia文章是否存在。例如,https://en.wikipedia.org/wiki/Food 存在,但是https://en.wikipedia.org/wiki/Fod 不会,页面只是说:“维基百科没有此名称的文章。”谢谢! 参考方案 >>> import urllib >>> prin…

    Python uuid4,如何限制唯一字符的长度 - python

    在Python中,我正在使用uuid4()方法创建唯一的字符集。但是我找不到将其限制为10或8个字符的方法。有什么办法吗?uuid4()ffc69c1b-9d87-4c19-8dac-c09ca857e3fc谢谢。 参考方案 尝试:x = uuid4() str(x)[:8] 输出:"ffc69c1b" Is there a way to…

    Python-如何检查Redis服务器是否可用 - python

    我正在开发用于访问Redis Server的Python服务(类)。我想知道如何检查Redis Server是否正在运行。而且如果某种原因我无法连接到它。这是我的代码的一部分import redis rs = redis.Redis("localhost") print rs 它打印以下内容<redis.client.Redis o…

    Python-crontab模块 - python

    我正在尝试在Linux OS(CentOS 7)上使用Python-crontab模块我的配置文件如下:{ "ossConfigurationData": { "work1": [ { "cronInterval": "0 0 0 1 1 ?", "attribute&…

    python asyncio run_forever或True - python

    我应该在代码中替换while True(不使用asyncio)还是应该使用asyncio事件循环来实现相同的结果。目前,我正在处理某种与“ zeromq”连接的“工作者”,接收一些数据,然后对外部工具(服务器)执行一些请求(http)。一切都以普通的阻塞IO编写。使用asyncio事件循环摆脱while True: ...是否有意义?将来可能会用asynci…