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

Python Asyncio服务器客户端断开后无法停止,添加writer.close()生效的原因?

问题现象与疑问
  • 现象:当有客户端连接过(即使客户端已关闭socket),Python Asyncio服务器无法正常关闭;若10秒内无客户端连接则可正常关闭。
  • 操作步骤:
    1. 运行server.py
    2. 运行client.py——客户端连接后立即关闭socket
  • 结果:服务器挂起,无法关闭
  • 疑问:在clientHandler函数中添加writer.close()可解决该问题,请问此操作生效的原因是什么?相关说明文档在哪里?

服务器代码

# server
from os import path as ospath
import asyncio
import socket as Socket
import logger as log

logger = log.getLogger(fileName=ospath.join('log', 'server.log'), initialize=True)

class Client():
    def __init__(self, socket:Socket=None, addr:tuple=None) -> None:
        self.socket = socket
        self.addr = addr
        self.connected = False

class App():
    def __init__(self) -> None:
        self.quit = False
        self.clients = []

async def clientHandler(reader, writer):
    logger.info('client handler starting')

async def main():
    logger.info("server app starting")
    app = App()
    
    # start socket server
    ipaddr = Socket.gethostbyname(Socket.gethostname())
    port = 32843
    logger.info(f'starting socket server ({ipaddr}:{port})')
    server = await asyncio.start_server(clientHandler, ipaddr, port=32843)

    logger.info('waiting for client to connect...')
    await asyncio.sleep(10)
    logger.info('closing server')
    server.close()

    await server.wait_closed()
    logger.info('server closed')

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

客户端代码

# client
import socket

dest_ip = socket.gethostbyname(socket.gethostname())
dest_port = 32843
encoder = "utf-8"

client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect((dest_ip, dest_port))

client_socket.shutdown(socket.SHUT_RDWR)
client_socket.close()

解答

生效原因

客户端连接Asyncio服务器后,服务器会为该连接生成StreamReader和StreamWriter实例,它们绑定着底层的socket连接资源。即便客户端主动关闭了自己的socket,服务器端的StreamWriter并不会自动关闭对应的连接,这个未释放的连接会被服务器标记为活跃状态。

当调用server.close()时,服务器会停止接收新连接,但会等待所有已建立的连接处理完毕或关闭后,才会完成整个关闭流程。之前的clientHandler没有处理连接关闭,服务器会一直等待这个未关闭的连接,从而导致挂起无法退出。

添加writer.close()后,会主动关闭服务器端对应的socket连接,释放相关资源。服务器检测到所有连接都已关闭,就能顺利完成await server.wait_closed()的等待,正常退出。

相关文档说明

Python官方文档的**Asyncio 流(Streams)**章节中,明确了StreamWriter.close()的作用:关闭writer对应的传输对象,这会直接关闭底层的socket连接。需要注意的是,close()是非阻塞操作,如果需要等待关闭完成,可以调用await writer.wait_closed()。

另外,关于start_server创建的服务器关闭逻辑,文档提到server.close()仅停止接受新连接,必须等所有已处理连接的传输都关闭后,server.wait_closed()才会执行完成。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 22:08:19