簡體   English   中英

如何在asyncio服務器中實現超時?

[英]How to implement timeout in asyncio server?

下面是一個簡單的echo服務器。 但如果客戶端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")

第二部分仍然存在。 有沒有更好的方法來實現超時?


UPDATE2

使用wait_for完成代碼。 不再需要超時代碼。 檢查以下解決方案

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")

我在建立連接時使用以下代碼。 我建議你的代碼使用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

有沒有更好的方法來實現超時?

您可以使用asyncio.wait_for而不是timeout 它有類似的語義,但已經附帶asyncio。 此外,您可以等待將來返回以檢測是否已發生超時。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM