Weclaw 请求路由实战:一个 request_id 如何在 800 个并发连接中精准找到目标浏览器?

Weclaw 请求路由实战:一个 request_id 如何在 800 个并发连接中精准找到目标浏览器?

系列文章第 03 篇 - request_id 在分布式系统中的生命周期


📚 专栏信息

《从零到一构建跨平台 AI 助手:WeClaw 实战指南》专栏

专栏定位:面向开发者和技术决策者的实战专栏,用真实案例和完整代码带你理解如何构建生产级 AI 应用

本系列共 17 篇,分为七大模块

📖 模块一【通讯架构设计】(3 篇):混合通讯、设备绑定、请求路由

🔧 模块二【核心技术实现】(4 篇):WebSocket 路由、心跳重连、离线队列

🛡️ 模块三【安全与治理】(3 篇):密钥管理、Token 吊销、速率限制

🔍 模块四【调试与监控】(2 篇):全链路追踪、日志分析

💡 模块五【问题诊断实战】(3 篇):典型问题排查与修复

⚙️ 模块六【性能优化】(1 篇):启动速度、内存优化

🚀 模块七【架构演进史】(1 篇):从 0 到 1 的完整历程

本文是模块一第 3 篇,将带您深入理解 UUID 生成算法、内存路由表设计、请求过期清理机制与多实例隔离策略。


👨‍💻 作者与项目

作者简介 :翁勇刚 WENG YONGGANG

新概念龙虾-WeClaw 开发团队负责人,一群专注于跨平台 AI 应用的实践者
理念:"再复杂的技术,也能用代码讲清楚"


📝 摘要

本文结构概览

本文从一个"消息发错浏览器"的生产事故出发,剖析请求路由的核心挑战,详解 UUID 生成算法、四层内存映射表设计、asyncio 定时清理机制,随后还原一起 request_id 不匹配导致的响应丢失问题排查过程,最后给出多浏览器实例隔离方案和最佳实践清单。

背景:在 Weclaw PWA 多标签页使用场景中,用户同时打开 3 个浏览器标签页与 AI 对话,服务器收到 LLM 响应后必须精准推送回发起请求的那个标签页,而不能张冠李戴。

核心问题:如何在 800+ 并发 WebSocket 连接中,让每个响应都能准确找到发起请求的客户端?如何管理海量路由表的内存占用和过期清理?如何处理多浏览器实例的消息隔离?

解决方案:采用客户端生成 UUID 作为 request_id,通过四层内存映射表(request_id→session_id→client_id→connection)实现 O(1) 查找,用 asyncio 定时任务实现过期清理,引入 Tab ID 机制隔离多实例。

关键成果

  • 路由查找时间稳定在 0.05ms 以内(O(1) 字典查找)
  • 支持 800+ 并发连接无消息错发(精准路由)
  • 自动清理过期路由项,内存占用降低 67%(定时清理)
  • 多标签页场景下消息隔离成功率 100%(Tab ID 机制)

适合读者:有 Python 基础,对分布式系统、消息路由、内存管理感兴趣的开发者

阅读时长:约 10 分钟

关键词request_idUUID消息路由内存映射表asyncio 定时任务多实例隔离WebSocket


一、为什么要"请求路由"?------从一次消息错发事故说起

1.1 场景重现:当 AI 把回复发错了窗口

想象这个场景:

  • 你在 Chrome 中打开 3 个 WinClaw 标签页,分别处理不同的任务
  • 标签页 A 在整理会议纪要,标签页 B 在写代码,标签页 C 在查资料
  • 你同时在三个窗口发送消息,服务器几乎同时收到请求
  • 10 秒后,标签页 A 收到了标签页 B 的回复!整个对话乱套了

问题出在哪?让我们看看三种路由方案的特性:

路由方案 像什么?(比喻) 适用场景 局限性
广播模式 大喇叭喊话 聊天室、公告推送 所有客户端都收到,浪费带宽
Session 路由 按房间号投递 简单会话管理 无法区分同一 session 的多个请求
Request-ID 路由 快递单号追踪 精准消息投递 需要生成和管理大量 ID

1.2 为什么不由服务器生成 request_id?

初学者常问:"服务器收到请求后生成一个 ID,然后记住这个 ID 不行吗?"

答案是:服务器生成的 ID 无法追溯请求来源

python 复制代码
# ❌ 错误示范:服务器生成 ID
class BadRequestIdGeneration:
    async def handle_request(self, ws, message):
        # 问题 1:服务器不知道这是哪个请求的响应
        request_id = generate_uuid()  # 服务器自己生成
        response = await call_llm(message)
        await send_to_client(ws, response)  # 怎么知道发给谁?
        
        # 问题 2:如果有 100 个并发请求,完全混乱
python 复制代码
# ✅ 正确做法:客户端生成 ID,服务器原样返回
class GoodRequestIdGeneration:
    async def handle_request(self, ws, message):
        # 客户端已经生成了 request_id
        request_id = message.get("request_id")  # 从消息中提取
        
        # 处理业务逻辑...
        response = await call_llm(message)
        
        # 关键:响应中使用同一个 request_id
        response["request_id"] = request_id
        
        # 通过 request_id 找到对应的连接并发送
        await route_response(request_id, response)

1.3 核心挑战是什么?

现在我们有三个"必须解决"的问题:

  1. 精准性:800 个并发连接中,响应必须找到正确的那个
  2. 时效性:路由表必须在毫秒级完成查找
  3. 内存效率:不能无限增长,必须自动清理过期项

如何在三者之间找到平衡点?

答案就在后面的四层映射表 + UUID 算法 + 定时清理机制


二、核心概念解析 ------ 用"快递系统"理解请求路由

2.1 什么是"request_id"?

官方定义

Request ID(请求标识符)是在分布式系统中用于唯一标识一次请求的 UUID 字符串,贯穿请求的整个生命周期,用于链路追踪、日志关联和响应路由。

大白话解释

就像快递单号,你寄快递时生成一个单号,包裹在整个运输过程中都用这个单号追踪,最后收件人凭单号签收。

生活化比喻

复制代码
┌───────────────────────────────────────┐
│         快递单号追踪系统               │
│  寄件:生成单号 SF1234567890           │
│  运输:北京→深圳→广州(全程追踪)     │
│  签收:凭单号确认收件人               │
│  特点:一单一号、全程可溯、精准投递   │
└───────────────────────────────────────┘
           ↓ 类比
┌───────────────────────────────────────┐
│         Request-ID 路由系统            │
│  请求:客户端生成 UUID abc-123-def     │
│  处理:PWA→服务器→LLM→服务器(全链路)│
│  响应:凭 request_id 找到发起请求的浏览器│
│  特点:一请求一 ID、全链路追踪、零错发 │
└───────────────────────────────────────┘

2.2 工作原理:路由表如何运行?

看图理解:

复制代码
┌─────────────────────────────────────────────────────────┐
│              内存路由表 (BridgeConnectionManager)        │
│                                                         │
│  第 1 层:request_id → session_id                       │
│  ┌──────────────────────────────────────────────────┐  │
│  │ "req_001" → "sess_abc"                           │  │
│  │ "req_002" → "sess_def"                           │  │
│  └──────────────────────────────────────────────────┘  │
│                         ↓                               │
│  第 2 层:session_id → client_id                        │
│  ┌──────────────────────────────────────────────────┐  │
│  │ "sess_abc" → "client_xyz"                        │  │
│  │ "sess_def" → "client_uvw"                        │  │
│  └──────────────────────────────────────────────────┘  │
│                         ↓                               │
│  第 3 层:client_id → connection_id                     │
│  ┌──────────────────────────────────────────────────┐  │
│  │ "client_xyz" → conn_123                          │  │
│  │ "client_uvw" → conn_456                          │  │
│  └──────────────────────────────────────────────────┘  │
│                         ↓                               │
│  第 4 层:connection_id → WebSocket 对象                 │
│  ┌──────────────────────────────────────────────────┐  │
│  │ conn_123 → <WebSocket object at 0x7f8b1c2d3e4f>  │  │
│  │ conn_456 → <WebSocket object at 0x7f8b1c2d3e5a>  │  │
│  └──────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────┘

关键步骤

  1. 请求到达 :客户端发送 {"request_id": "req_001", "message": "..."}
  2. 建立映射request_id → session_id → client_id → connection
  3. LLM 处理:服务器调用 LLM API,等待响应
  4. 响应路由:从 response["request_id"] 提取 ID,反向查找 WebSocket 对象
  5. 精准推送ws.send_json(response) 给特定连接
  6. 清理过期项:定时任务删除超过 5 分钟的映射

2.3 对比:客户端生成 vs 服务端生成

维度 客户端生成 服务端生成 区别
可追溯性 知道请求来源 无法追溯 客户端生成便于溯源
并发安全 天然隔离 需加锁防冲突 客户端生成无锁设计
链路追踪 全链路一致 可能多次变化 客户端生成便于监控
实现复杂度 简单 复杂 客户端生成代码更少

为什么选择客户端生成?

因为 WinClaw 面对的是高并发实时通信场景:客户端生成避免了服务器端的锁竞争,天然支持分布式追踪,且实现更简单!


三、实战代码详解 ------ 手把手教你实现请求路由系统

3.1 数据结构设计

首先定义核心路由表:

python 复制代码
# winclaw_server/remote_server/core/connection_manager.py
from typing import Dict, Optional, Any
from dataclasses import dataclass, field
import time
import asyncio

@dataclass
class RouteEntry:
    """路由表条目"""
    request_id: str
    session_id: str
    client_id: str
    connection_id: int
    created_at: float = field(default_factory=time.time)
    expires_at: float = field(default=0.0)
    
    def __post_init__(self):
        # 默认 5 分钟过期
        if self.expires_at == 0.0:
            self.expires_at = self.created_at + 300

class BridgeConnectionManager:
    """桥接连接管理器------包含请求路由功能"""
    
    def __init__(self):
        # === 四层映射关系 ===
        
        # 第 1 层:request_id → RouteEntry
        self._request_routes: Dict[str, RouteEntry] = {}
        
        # 第 2 层:session_id → set[request_id] (一个 session 多个请求)
        self._session_requests: Dict[str, set] = {}
        
        # 第 3 层:client_id → WebSocket 连接对象
        self._client_connections: Dict[int, Any] = {}
        
        # 第 4 层:connection_id → request_ids (反向索引,用于清理)
        self._connection_requests: Dict[int, set] = {}
        
        # === 定时清理任务 ===
        self._cleanup_task: Optional[asyncio.Task] = None
    
    async def start_cleanup_loop(self, interval: int = 60):
        """启动定时清理任务(每 60 秒检查一次)"""
        async def cleanup_loop():
            while True:
                await asyncio.sleep(interval)
                await self._cleanup_expired_routes()
        
        self._cleanup_task = asyncio.create_task(cleanup_loop())

字段说明

  • _request_routes: 核心路由表,通过 request_id 快速找到连接
  • _session_requests: 管理 session 级别的多个请求(支持批量清理)
  • _client_connections: 存储 WebSocket 连接对象
  • _connection_requests: 反向索引,用于连接断开时批量清理
  • _cleanup_task: 定时清理过期路由项

设计亮点

  1. 四层索引:正向查找 O(1),反向清理 O(1)
  2. 过期时间:每个路由项自带 TTL,防止内存泄漏
  3. 批量清理:支持按 session、按 connection 批量删除

3.2 核心方法实现

方法 1:添加路由映射
python 复制代码
async def add_request_route(
    self,
    request_id: str,
    session_id: str,
    client_id: str,
    connection: Any  # WebSocket 对象
) -> bool:
    """添加请求路由映射
    
    Args:
        request_id: 请求 ID(由客户端生成)
        session_id: 会话 ID(从连接管理器获取)
        client_id: 客户端 ID(从设备指纹派生)
        connection: WebSocket 连接对象
    
    Returns:
        bool: 是否添加成功
    """
    
    # ✅ 关键:生成唯一的 connection_id
    connection_id = id(connection)
    
    # 创建路由条目
    route_entry = RouteEntry(
        request_id=request_id,
        session_id=session_id,
        client_id=client_id,
        connection_id=connection_id,
        expires_at=time.time() + 300  # 5 分钟后过期
    )
    
    # ⚠️ 注意:四层映射必须原子操作
    self._request_routes[request_id] = route_entry
    self._session_requests.setdefault(session_id, set()).add(request_id)
    self._client_connections[connection_id] = connection
    self._connection_requests.setdefault(connection_id, set()).add(request_id)
    
    logger.debug(f"添加路由映射:request_id={request_id[:16]}...")
    return True

代码解析

  • 第 19-26 行:创建路由条目,设置 5 分钟过期时间
  • 第 29-32 行:四层映射建立索引,确保后续 O(1) 查找
  • 第 35 行:记录调试日志(生产环境建议用 DEBUG 级别)

为什么这么简单?

因为这是纯内存操作,字典插入时间复杂度 O(1),比数据库查询快 1000 倍!

方法 2:路由响应消息
python 复制代码
async def route_response(
    self,
    request_id: str,
    response: dict
) -> bool:
    """路由响应消息到发起请求的客户端
    
    Args:
        request_id: 请求 ID(从 LLM 响应中提取)
        response: 响应字典(包含 response["request_id"])
    
    Returns:
        bool: 是否发送成功
    """
    
    # ✅ 关键:先从路由表查找
    route_entry = self._request_routes.get(request_id)
    if not route_entry:
        logger.warning(f"未找到路由:request_id={request_id}")
        return False
    
    # 获取 WebSocket 连接
    connection = self._client_connections.get(route_entry.connection_id)
    if not connection:
        logger.error(f"连接不存在:connection_id={route_entry.connection_id}")
        return False
    
    try:
        # ⚠️ 注意:确保响应中包含 request_id
        response["request_id"] = request_id
        
        # 发送消息
        await connection.send_json(response)
        
        # 可选:立即删除路由项(一次性请求)
        # await self.remove_request_route(request_id)
        
        logger.debug(f"响应已路由:request_id={request_id[:16]}...")
        return True
        
    except Exception as e:
        logger.error(f"发送响应失败:{e}")
        return False

代码解析

  • 第 19-24 行:从路由表查找,O(1) 时间复杂度
  • 第 27-30 行:获取 WebSocket 连接对象
  • 第 34-35 行:确保响应中包含 request_id(防御性编程)
  • 第 38-41 行:发送消息并记录日志
方法 3:定时清理过期路由
python 复制代码
async def _cleanup_expired_routes(self):
    """清理过期的路由项(每 60 秒执行一次)"""
    
    current_time = time.time()
    expired_requests = []
    
    # 找出所有过期的 request_id
    for request_id, route in self._request_routes.items():
        if route.expires_at < current_time:
            expired_requests.append(request_id)
    
    if not expired_requests:
        return
    
    # 批量删除
    for request_id in expired_requests:
        await self.remove_request_route(request_id)
    
    logger.info(f"清理了 {len(expired_requests)} 个过期路由项")

易错点 1:遍历中删除的安全问题

python 复制代码
# ❌ 错误示范:遍历字典时直接删除
for request_id, route in self._request_routes.items():
    if route.expires_at < current_time:
        del self._request_routes[request_id]  # RuntimeError: 字典大小变化!

# ✅ 正确写法:先收集再删除
expired = [req_id for req_id, route in self._request_routes.items() 
           if route.expires_at < current_time]
for request_id in expired:
    del self._request_routes[request_id]

教训:Python 字典遍历时不能修改大小,必须先收集 keys 再删除!

3.3 UUID 生成算法

客户端 UUID 生成(TypeScript)
typescript 复制代码
// pwa/src/utils/uuid.ts

/**
 * 生成 UUID v4(基于随机数的 UUID)
 * @returns string 格式:"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"
 */
export function generateUUID(): string {
  // ✅ 关键:使用加密安全的随机数
  const array = new Uint8Array(16);
  crypto.getRandomValues(array);
  
  // 设置版本号为 4
  array[6] = (array[6] & 0x0f) | 0x40;
  
  // 设置变体为 RFC 4122
  array[8] = (array[8] & 0x3f) | 0x80;
  
  // 转为十六进制字符串
  const hex = Array.from(array).map(b => b.toString(16).padStart(2, '0'));
  
  // 按照 UUID 格式拼接
  return [
    hex.slice(0, 4).join(''),
    hex.slice(4, 6).join(''),
    hex.slice(6, 8).join(''),
    hex.slice(8, 10).join(''),
    hex.slice(10, 16).join('')
  ].join('-');
}

// 使用示例
const requestId = generateUUID();
// 输出:"a3f5b2c8-d9e1-4f6a-b7c3-e5d4f6a8b9c0"

代码解析

  • 第 10-11 行:使用 Web Crypto API 生成 16 字节随机数
  • 第 14-17 行:设置 UUID 版本号(第 7 位)和变体(第 9 位)
  • 第 23-31 行:按照 UUID 标准格式拼接(8-4-4-4-12)

为什么选择 UUID v4?

因为 v4 基于随机数,生成简单,碰撞概率极低(10^37 次生成才可能碰撞一次),完全满足分布式系统需求!


四、问题诊断与修复 ------ 从"响应丢失"到完美匹配

4.1 问题现象:PWA 收不到响应

用户报告

"我发消息后,界面一直转圈,服务器日志显示'发送成功',但浏览器就是没收到响应。"

服务器日志

复制代码
2026-03-13 15:42:18 | bridge | INFO | 收到请求:request_id=req_abc123
2026-03-13 15:42:20 | llm | INFO | LLM 响应生成完毕
2026-03-13 15:42:20 | bridge | INFO | 路由响应:request_id=req_abc123
2026-03-13 15:42:20 | bridge | WARNING | 未找到路由:request_id=req_abc123

奇怪:明明添加了路由映射,为什么查找时说"未找到"?

4.2 根因分析:request_id 被替换

排查步骤

1️⃣ 检查添加路由的时机

python 复制代码
# 查看代码
async def handle_websocket_message(ws, message):
    request_id = message.get("request_id")
    await conn_manager.add_request_route(request_id, session_id, client_id, ws)
    
    # 调用 LLM
    response = await call_llm_api(message)
    await conn_manager.route_response(request_id, response)

2️⃣ 检查 LLM 响应

python 复制代码
# 打印 LLM 返回的数据
print(response)
# 输出:{"content": "...", "request_id": "req_xyz789"}  ← 不一样!

3️⃣ 发现问题

复制代码
客户端发送 → request_id: "req_abc123"
LLM 响应   → request_id: "req_xyz789"  ← 被替换了!
路由查找   → 查找 "req_abc123" → 找不到

根本原因:LLM API 返回的响应中包含了它自己生成的 request_id,覆盖了客户端的原始 ID!

4.3 修复方案:保护原始 request_id

修复 1:提前备份原始 ID

python 复制代码
# ✅ 修改后
async def handle_websocket_message(ws, message):
    # 提前备份客户端的 request_id
    original_request_id = message.get("request_id")
    
    # 添加到路由表
    await conn_manager.add_request_route(original_request_id, session_id, client_id, ws)
    
    # 调用 LLM(LLM 可能会修改 request_id)
    response = await call_llm_api(message)
    
    # 关键:使用原始的 request_id 路由响应
    await conn_manager.route_response(original_request_id, response)

修复 2:禁止 LLM 修改 request_id

python 复制代码
# ✅ 修改后:调用 LLM 时明确传递参数
async def call_llm_api(message: dict) -> dict:
    # 不要将 request_id 传递给 LLM
    llm_input = {
        "messages": message["messages"],
        "model": message["model"]
        # 不包含 request_id!
    }
    
    response = await litellm.acompletion(**llm_input)
    
    # 不要覆盖 request_id
    # response 中不应该有 request_id 字段
    
    return response

验证结果

复制代码
✅ 步骤 1:客户端发送 request_id="req_001"
✅ 步骤 2:路由表记录 request_id="req_001"
✅ 步骤 3:LLM 响应不包含 request_id
✅ 步骤 4:使用原始 ID 路由,PWA 成功接收

4.4 经验教训:学到了什么?

Checklist

  • 客户端生成的 request_id 必须在进入 LLM 调用前提前备份
  • LLM API 调用不应包含 request_id 字段(避免混淆)
  • 响应路由时必须使用客户端的原始 ID,而非 LLM 生成的 ID
  • 日志必须打印 request_id,便于链路追踪

避坑指南

  1. request_id 是契约:前后端约定好的 ID,中间任何环节都不能擅自修改
  2. 端到端原则:request_id 应该从客户端发出,最终回到客户端,中途不变
  3. 防御性编程:即使 LLM SDK 试图修改 request_id,也要在业务层保护原始值

五、性能优化与最佳实践

5.1 性能瓶颈分析

Profiling 数据

复制代码
add_request_route():   0.02ms  (字典插入)
route_response():      0.05ms  (字典查找 + 网络发送)
cleanup_expired():     1.5ms   (遍历 + 批量删除,平均每 60 秒)
generate_uuid():       0.01ms  (随机数生成)

结论:路由操作本身极快(微秒级),主要耗时在网络 IO。

5.2 优化策略

策略 1:弱引用防止内存泄漏
python 复制代码
# ✅ 使用 weakref 管理连接对象
import weakref

class BridgeConnectionManager:
    def __init__(self):
        # 使用 WeakValueDictionary 存储连接
        self._client_connections: weakref.WeakValueDictionary = weakref.WeakValueDictionary()
    
    def add_connection(self, connection_id: int, connection: Any):
        # 弱引用:当 WebSocket 对象被垃圾回收时,字典项自动消失
        self._client_connections[connection_id] = connection

代价 :增加弱引用管理开销
收益:彻底防止连接对象泄漏

策略 2:分层过期时间
python 复制代码
# ✅ 根据请求类型设置不同过期时间
class RouteEntry:
    def __init__(self, request_type: str, ...):
        if request_type == "streaming":
            self.expires_at = time.time() + 600  # 流式请求 10 分钟
        elif request_type == "single_turn":
            self.expires_at = time.time() + 120  # 单次对话 2 分钟
        else:
            self.expires_at = time.time() + 300  # 默认 5 分钟

代价 :增加判断逻辑
收益:精细化内存管理,减少无效占用

5.3 最佳实践总结

Do's(推荐做法):

  • ✅ 客户端生成 UUID v4 作为 request_id
  • ✅ 使用四层映射表实现 O(1) 查找
  • ✅ 实施定时清理机制(60 秒间隔)
  • ✅ 提前备份原始 request_id,防止被覆盖
  • ✅ 日志中始终包含 request_id(至少前 16 位)

Don'ts(避免做法):

  • ❌ 在遍历字典时直接删除项
  • ❌ 将 request_id 传递给 LLM API(避免混淆)
  • ❌ 使用非加密随机数生成 UUID
  • ❌ 永久存储路由项(必须设置 TTL)
  • ❌ 忽略异常处理(网络发送可能失败)

黄金法则

request_id 是请求的生命线,从客户端发出到回到客户端,全程不可篡改。


六、总结与展望

6.1 核心要点回顾

本文讲解了请求路由机制的完整实现:

3 个关键点

  1. 客户端生成 UUID:避免服务器端锁竞争,天然支持分布式追踪
  2. 四层映射表设计:request_id→session_id→client_id→connection,O(1) 查找
  3. 定时清理机制:asyncio 定时任务自动删除过期路由项,防止内存泄漏

1 个核心公式

复制代码
请求路由 = UUID v4(客户端生成) + 四层映射表 (O(1) 查找) + asyncio 定时清理 (60 秒间隔)

6.2 下一步学习方向

前置知识

  • ✅ UUID 规范(RFC 4122)
  • ✅ Python 字典数据结构
  • ✅ asyncio 定时任务
  • ✅ WebSocket 协议基础

后续主题

  • 📖 下一篇:《第 04 篇:WebSocket 路由机制详解------从 BridgeConnectionManager 看消息转发艺术》
  • 🔜 下下一篇:《第 05 篇:心跳与重连机制------指数退避算法在 WebSocket 中的实践》

扩展阅读

6.3 互动环节

思考题

  1. 如果你的应用场景需要支持离线消息(客户端暂时断开),应该如何改造路由表?
  2. 如何在多服务器集群间共享路由信息?

讨论话题

在你的项目中,遇到过哪些消息路由的挑战?你是如何实现精准投递的?欢迎在评论区分享你的经验!


下期预告:《第 04 篇:WebSocket 路由机制详解》

  • 🗺️ BridgeConnectionManager 架构设计全景图
  • 🔗 四层映射关系深度剖析
  • 🎯 定点路由 vs 广播的选择策略
  • 🛡️ 降级兼容的设计模式

敬请期待!


附录 A:完整代码清单

文件路径 行数 作用
pwa/src/utils/uuid.ts 35 行 UUID 生成工具
winclaw_server/remote_server/core/connection_manager.py 280 行 连接管理器(含路由表)
winclaw_server/remote_server/api/websocket.py 95 行 WebSocket 处理器
winclaw_server/remote_server/services/llm_bridge.py 120 行 LLM 桥接服务
tests/test_request_routing.py 160 行 路由测试

总代码量 :约 690 行
关键方法 :10 个(add_request_route、route_response、cleanup_expired 等)
测试用例:22 个(覆盖路由添加、查找、清理、异常处理等场景)


附录 B:参考资料

  1. RFC 4122 - UUID Specification
  2. Python weakref Module
  3. OpenTracing - Distributed Tracing
  4. Asyncio Best Practices
  5. 上一篇:《第 02 篇:设备指纹绑定机制》
  6. 下一篇:《第 04 篇:WebSocket 路由机制详解》(待发布)

版权声明:本文为 CSDN 博主「翁勇刚」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。

原文链接https://blog.csdn.net/yweng18/article/details/159113089

相关推荐
望未来无悔2 小时前
实时传输的选择方案
websocket
2401_844221323 小时前
Python数据库操作:SQLAlchemy ORM指南
jvm·数据库·python
一起来学吧4 小时前
【OpenClaw系列教程】第一篇:OpenClaw 完整介绍——开源 AI 智能体平台
人工智能·ai·openclaw·养龙虾
白雨青4 小时前
国信 iQuant 自动国债逆回购实战:Python 自动化闲钱理财
python·量化策略·量化交易·国债逆回购
qq_404265834 小时前
用Python批量处理Excel和CSV文件
jvm·数据库·python
才兄说5 小时前
机器人租售效果好吗?任务前对齐需求
python
一起来学吧5 小时前
【OpenClaw系列教程】第二篇:OpenClaw 是什么? 开源AI智能体平台
人工智能·ai·openclaw
喵手5 小时前
Python 爬虫实战:构建开源主题模板版本库
爬虫·python·数据采集·爬虫实战·零基础python爬虫教学·开源主题·采集开源主题模版本库
qq_418101775 小时前
使用Scikit-learn进行机器学习模型评估
jvm·数据库·python