asyncio.start_server() 是启动异步服务的最稳妥方式,需 await server.serve_forever() 才真正运行;handle_client 中须用 readuntil/readexactly 避免粘包,drain 确保响应发出,request_id 应绑定连接上下文而非全局字典。

用 asyncio.start_server() 启动服务,别手写 socket 循环
直接调用 asyncio.start_server() 是最稳妥的起点。它自动处理监听、accept、错误重试和连接拒绝逻辑;自己用 socket.socket().bind() + while True + select 不仅重复造轮子,还容易漏掉 SIGPIPE、EMFILE 等系统级异常。
常见错误是把 start_server 当成“启动后就完事了”,其实它只返回一个 Server 对象,必须 await server.serve_forever() 才真正运行。没这句,程序会立即退出。
- 务必传入
start_serving=False用于测试或延迟启动 - 设置
backlog=1024(而非默认 100),避免高并发下连接被内核丢弃 - 禁用
ssl参数除非真需要 TLS——加了 SSL 握手开销会吃掉 15%+ QPS
handle_client 协程里只做读、解析、响应三件事
每个客户端连接由一个独立协程 async def handle_client(reader, writer) 处理,这是性能关键点:它不能阻塞、不能做 CPU 密集计算、更不能 await 全局锁。
典型陷阱是把 AI 推理、数据库查询、文件读写这些同步操作直接塞进这个协程里。结果就是整个事件循环卡住,其他连接全等。
立即学习“Python免费学习笔记(深入)”;
- 耗时操作一律用
loop.run_in_executor(None, sync_func, *args)拆到线程池 - 读取必须用
await reader.readuntil(b'\n')(JSON 行)或await reader.readexactly(4)(protobuf 头),禁用read(1024)——否则粘包必现 - 写响应后必须
await writer.drain(),否则操作系统缓冲区满时write()会静默失败,客户端收不到数据
request_id 生命周期必须绑定连接上下文
server 端绝不能维护全局 futures 字典。一旦 client 重连或 server 重启,旧 request_id 还在内存里,新响应一来就错配到别的 pending 请求上。
安全做法是:每个新连接生成唯一 session_id(比如 int(time.time() * 1000) & 0xffffffff),再为该连接内请求递增 seq_num,组合成 f"{session_id}_{seq_num}"。server 只查当前连接的本地字典。
- client 发起连接时生成并缓存
session_id,后续所有请求都带这个前缀 - server 在
handle_client开头初始化空字典:pending = {},生命周期与协程一致 - 收到请求后解析出完整
req_id,查pending[req_id]并set_result(),不查全局表
协议选 JSON 行还是 protobuf?看阶段,别早优化
开发期无脑用 JSON 行协议(json.dumps(obj) + '\n')。它能用 telnet localhost 8000 直连调试,响应可读,字段增删零成本;上线压测发现序列化占 CPU 超过 20%,再切 protobuf。
但切 protobuf 时必须加长度头,且两端严格对齐:struct.pack("!I", len(payload)) + payload。少一个 readexactly(4),网络抖动时就会卡死。
- client 发送前:先序列化 → 计算长度 → 打包 header →
writer.write(header + payload) - server 接收时:先
await reader.readexactly(4)→ 解出 size → 再await reader.readexactly(size) - 永远不用
reader.read()或reader.readline()解 protobuf,它们依赖分隔符,而 protobuf 二进制里可能含\n
连接复用、超时控制、错误清理这些细节,不写进 handle_client 主体里,很容易被忽略。尤其是 writer.close() 前没 await writer.wait_closed(),连接可能半关闭,下次复用时读到残包。



















