You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在异步上下文管理器中使用多Socket服务?连接被立即关闭问题

问题根源

你遇到的问题是因为async with块在调用asyncio.create_task()后立刻执行完毕了——create_task只会把协程交给事件调度器,不会阻塞当前代码。所以上下文管理器直接进入__aexit__方法,把刚建立的Socket连接给关了,导致后续的echo任务根本没法正常通信。

解决办法

这里给两个实用的修改方案,按需选择:

方案1:串行处理连接(简单直接)

如果你的服务器不需要同时处理多个连接,直接在async with块里等待任务完成就行,这样连接会保持到任务结束才关闭:

修改connection_listener方法:

async def connection_listener(self, server_socket):
    while True:
        async with ConnectedSocket(server_socket) as conn:
            task = asyncio.create_task(self.echo(conn))
            self.tasks.append(task)
            await task  # 等echo任务做完再退出上下文管理器

方案2:并发处理连接(适合多客户端场景)

如果要支持同时多个客户端连接,就得调整上下文管理器的逻辑,让连接的关闭由处理任务自己控制,而不是上下文管理器自动关闭:

第一步:修改ConnectedSocket类

class ConnectedSocket:
    def __init__(self, server_socket):
        self._connection = None
        self._server_socket = server_socket

    async def __aenter__(self):
        print("Entering context manager, waiting for connection")
        loop = asyncio.get_event_loop()
        conn, addr = await loop.sock_accept(self._server_socket)
        conn.setblocking(False)
        self._connection = conn
        print("Accepted a connection")
        return self  # 返回整个实例,方便后续调用close方法

    async def __aexit__(self, exc_type, exc_val, exc_tb):
        print("Exiting context manager")
        # 这里不再主动关闭连接,交给任务处理完后再关

    def close(self):
        if self._connection:
            self._connection.close()
            print("Closed connection")

第二步:修改echo和connection_listener方法

async def connection_listener(self, server_socket):
    while True:
        async with ConnectedSocket(server_socket) as sock_wrapper:
            # 把包装后的实例传给echo任务
            task = asyncio.create_task(self.echo(sock_wrapper))
            self.tasks.append(task)

async def echo(self, sock_wrapper: ConnectedSocket) -> None:
    conn = sock_wrapper._connection
    try:
        while data := await self.loop.sock_recv(conn, 1024):
            if data == b'exit\r\n':
                break
            print(data)
    finally:
        # 不管任务正常结束还是异常,都关闭连接
        sock_wrapper.close()
测试结果

修改后重新运行服务器,用telnet测试:

Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
hello world
hello world
exit
Connection closed by foreign host.

现在可以正常收发数据,直到发送exit指令后连接才会关闭,完美解决问题。

内容的提问来源于stack exchange,提问作者Alex

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 00:14:53