簡體   English   中英

使用異步流在 TCP 服務器上保持無限連接打開?

[英]Keep indefinite connections open on TCP server with asyncio streams?

我試圖了解如何將異步流用於多個連接,這些連接將繼續發送消息,直到預定義的條件或套接字超時。 查看 Python 文檔,他們為基於異步流的 TCP 服務器提供了以下示例:

import asyncio

async def handle_echo(reader, writer):
    data = await reader.read(100)
    message = data.decode()
    addr = writer.get_extra_info('peername')

    print(f"Received {message!r} from {addr!r}")

    print(f"Send: {message!r}")
    writer.write(data)
    await writer.drain()

    print("Close the connection")
    writer.close()

async def main():
    server = await asyncio.start_server(
        handle_echo, '127.0.0.1', 8888)

    addrs = ', '.join(str(sock.getsockname()) for sock in server.sockets)
    print(f'Serving on {addrs}')

    async with server:
        await server.serve_forever()

asyncio.run(main())

我想做的更復雜,看起來更像這樣(很多是偽代碼,用大寫字母寫或省略了實現):

import asyncio

async def io_control(queue):
   while true:
      ...
# do I/O control in this function ... 

async def data_processing(queue):
   while true:
      ...
# perform data handling

async def handle_data(reader, writer):
    data = await reader.read()
    message = data.decode()
    addr = writer.get_extra_info('peername')

    print(f"Received {message!r} from {addr!r}")
    
    #do stuff with a queue - pass messages to other two async functions as needed        

    #keep open until something happens
    if(ERROR or SOCKET_TIMEOUT):
       writer.close()

async def server(queue):
    server = await asyncio.start_server(
        handle_data, '127.0.0.1', 8888)

    addrs = ', '.join(str(sock.getsockname()) for sock in server.sockets)
    print(f'Serving on {addrs}')

    async with server:
        await server.serve_forever()

async def main():

    queue_io = asyncio.Queue()
    queue_data = asyncio.Queue()
    
    asyncio.run(server(queue_data))
    asyncio.run(data_handling(queue_data))
    asyncio.run(io_control(queue_io))

asyncio.run(main())

這看起來可行嗎? 我不習慣使用協同程序(我來自更多的多線程范式),所以我不確定我所做的是否正確,或者我是否必須明確地包含 yield 或 do任何額外的東西。

如果我理解正確,您只需要 TCP 服務器就可以處理多個並發連接。 start_server function 應該已經為您提供了所需的一切。

第一個參數client_connected_cb是一個協程 function 每當客戶端建立連接時調用。 如果您在該 function 中引入一個循環(在您的示例代碼中handle_data ),您可以保持連接打開,直到滿足某些標准。 究竟什么條件會導致關閉連接取決於您,而實施細節顯然取決於此。 我能想象的最簡單的方法是這樣的:

import asyncio
import logging

log = logging.getLogger(__name__)

async def handle_data(reader, writer):
    while True:
        data = (await reader.readline()).decode().strip()
        if not data:
            log.debug("client disconnected")
            break
        response = await your_data_processing_function(data)
        writer.write(response.encode())
        await writer.drain()

...

async def main():
    server = await asyncio.start_server(handle_data, '127.0.0.1', 8888)
    async with server:
        await server.serve_forever()

if __name__ == '__main__':
    asyncio.run(main())

理論上並發連接數沒有限制。

如果您的client_connected_cb是協程 function,則每個新連接都會為事件循環安排一個新任務 這就是並發的來源。 然后魔法發生在await來自客戶端的新數據時; 這就是事件循環可以將執行切換到另一個協程的地方。 這一切都發生在幕后,可以這么說。

如果您想引入超時,您可以將可等待的readline協程包裝在wait_for中,然后捕獲TimeoutError退出循環。

希望這可以幫助。

暫無
暫無

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

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