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

如何关闭承载同步HTTPServer的异步任务?解决活跃连接阻塞退出问题

问题解决:带活跃连接时Python HTTP服务器无法按时退出

问题根源

当存在活跃连接(如netcat保持的长连接)时,TCPServer.shutdown()仅会停止服务器接受新连接,但会等待当前活跃连接的请求处理完成后才会退出serve_forever()循环。如果连接一直保持,服务器就会卡住,无法响应关闭指令。

解决方案

自定义服务器类,跟踪所有活跃的客户端连接,在关闭时主动断开这些连接,强制终止正在处理的请求,让serve_forever()快速退出。

修改后的完整代码

import asyncio
import http.server
import socketserver
import socket


class StoppableHTTPServer(socketserver.TCPServer):
    allow_reuse_address = True

    def __init__(self, server_address, RequestHandlerClass):
        super().__init__(server_address, RequestHandlerClass)
        self.active_connections = set()

    def process_request(self, request, client_address):
        # 记录当前活跃的客户端连接
        self.active_connections.add(request)
        try:
            super().process_request(request, client_address)
        finally:
            # 请求处理完毕后移除记录
            self.active_connections.discard(request)

    def stop(self):
        # 停止接受新连接
        self.shutdown()
        # 主动关闭所有活跃客户端连接
        for conn in self.active_connections:
            try:
                conn.shutdown(socket.SHUT_RDWR)
                conn.close()
            except Exception:
                # 忽略关闭时的异常(如连接已断开)
                pass
        # 关闭服务器自身的监听套接字
        self.server_close()
        
Handler = http.server.SimpleHTTPRequestHandler

def blocking_function(server):
    print("This is a blocking function.")
    with server:
        print("Serving on port 80")
        # 缩短轮询间隔,加快shutdown指令的检测速度
        server.serve_forever(poll_interval=0.5)

async def main():
    server = StoppableHTTPServer(("", 80), Handler)
    task = asyncio.create_task(asyncio.to_thread(blocking_function, server))
    
    await asyncio.sleep(3)
    
    task.cancel()
    
    try:
        await task
    except asyncio.CancelledError:
        print("Task was cancelled.")
        server.stop()
    
    print("Back to event loop.")
    
asyncio.run(main())

关键修改说明

  1. 跟踪活跃连接:新增active_connections集合,通过重写process_request方法记录所有正在处理的客户端连接套接字。
  2. 强制断开连接:在stop方法中,先调用shutdown()停止接受新连接,再遍历关闭所有活跃客户端连接,打断正在阻塞的请求处理流程。
  3. 加快退出响应:给serve_forever()设置poll_interval=0.5,让服务器更频繁地检查是否收到shutdown请求,缩短退出延迟。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 23:41:14