[英]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.