Files
video_socket-server/.qoder/repowiki/zh/content/信令系统/WebSocket 信令处理器.md
2026-05-16 13:24:02 +08:00

404 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# WebSocket 信令处理器
<cite>
**本文引用的文件**
- [websocket.ts](file://src/websocket.ts)
- [websockethandler.ts](file://src/class/websockethandler.ts)
- [offer.ts](file://src/class/offer.ts)
- [answer.ts](file://src/class/answer.ts)
- [candidate.ts](file://src/class/candidate.ts)
- [index.ts](file://src/index.ts)
- [server.ts](file://src/server.ts)
- [signaling.ts](file://src/signaling.ts)
- [httphandler.ts](file://src/class/httphandler.ts)
- [log.ts](file://src/log.ts)
- [options.ts](file://src/class/options.ts)
- [package.json](file://package.json)
- [websockethandler.test.ts](file://test/websockethandler.test.ts)
- [README.md](file://client/public/onebyone/README.md)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考量](#性能考量)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)
## 简介
本文件面向 WebSocket 信令处理器的技术文档,聚焦于 WebSocket 连接管理、连接组管理主机与参与者、Offer/Answer 协商流程、ICE 候选者传输、私有/公共模式差异、心跳与超时处理以及连接恢复策略。文档同时提供流程图与调试建议,帮助开发者快速理解与扩展系统。
## 项目结构
- 服务端入口与启动命令行参数解析、HTTPS/HTTP 服务创建、WebSocket 信令服务器启动。
- WebSocket 信令层:连接接入、消息分发、心跳与超时、广播与点对点路由。
- 数据模型Offer/Answer/Candidate 的封装,便于序列化与传输。
- HTTP 信令层(对比参考):提供轮询式信令的实现思路与数据持久化方案。
- 日志与配置:统一日志级别与输出格式;运行参数与模式配置。
```mermaid
graph TB
subgraph "服务端"
A["入口: index.ts<br/>解析参数/启动服务"]
B["HTTP 服务: server.ts<br/>静态资源/路由注册"]
C["WebSocket 信令: websocket.ts<br/>连接接入/消息分发"]
D["处理器: websockethandler.ts<br/>连接组/路由/心跳"]
E["数据模型: offer.ts/answer.ts/candidate.ts"]
F["HTTP 信令: signaling.ts/httphandler.ts<br/>轮询式信令(对比)"]
end
A --> B
B --> C
C --> D
D --> E
B --> F
```
图表来源
- [index.ts:52-91](file://src/index.ts#L52-L91)
- [server.ts:14-42](file://src/server.ts#L14-L42)
- [websocket.ts:6-117](file://src/websocket.ts#L6-L117)
- [websockethandler.ts:1-479](file://src/class/websockethandler.ts#L1-L479)
- [offer.ts:1-11](file://src/class/offer.ts#L1-L11)
- [answer.ts:1-8](file://src/class/answer.ts#L1-L8)
- [candidate.ts:1-12](file://src/class/candidate.ts#L1-L12)
- [signaling.ts:1-25](file://src/signaling.ts#L1-L25)
- [httphandler.ts:1-800](file://src/class/httphandler.ts#L1-L800)
章节来源
- [index.ts:13-109](file://src/index.ts#L13-L109)
- [server.ts:14-90](file://src/server.ts#L14-L90)
- [websocket.ts:6-117](file://src/websocket.ts#L6-L117)
## 核心组件
- WebSocket 信令服务器:负责连接接入、消息解析与分发、心跳与超时处理。
- 连接组管理器:维护每个连接组的主机与参与者集合,实现双向路由与广播。
- 数据模型封装Offer/Answer/Candidate 对象,承载 SDP 与 ICE 候选者元数据。
- 日志系统:统一日志级别与输出格式,便于调试与监控。
- HTTP 信令(对比):提供轮询式信令的数据持久化与查询能力,便于非 WebSocket 场景。
章节来源
- [websockethandler.ts:10-479](file://src/class/websockethandler.ts#L10-L479)
- [offer.ts:1-11](file://src/class/offer.ts#L1-L11)
- [answer.ts:1-8](file://src/class/answer.ts#L1-L8)
- [candidate.ts:1-12](file://src/class/candidate.ts#L1-L12)
- [log.ts:1-51](file://src/log.ts#L1-L51)
- [httphandler.ts:1-800](file://src/class/httphandler.ts#L1-L800)
## 架构总览
WebSocket 信令处理器采用“连接接入 -> 消息分发 -> 组内路由”的三层结构。连接接入由 websocket.ts 完成,消息分发与路由由 websockethandler.ts 实现,数据模型由 offer.ts/answer.ts/candidate.ts 提供。
```mermaid
sequenceDiagram
participant Client as "客户端"
participant WS as "WebSocket 服务器<br/>websocket.ts"
participant Handler as "处理器<br/>websockethandler.ts"
Client->>WS : "建立连接"
WS->>Handler : "add(ws)"
WS->>Client : "connect 消息(含 role/polite/participantId)"
Client->>WS : "offer/answer/candidate/ping/broadcast 等"
WS->>Handler : "根据 type 分派到 onOffer/onAnswer/onCandidate/onBroadcast"
Handler->>Handler : "根据 isPrivate/连接组/角色路由"
Handler-->>Client : "转发对应消息(可能携带 participantId)"
```
图表来源
- [websocket.ts:27-115](file://src/websocket.ts#L27-L115)
- [websockethandler.ts:63-479](file://src/class/websockethandler.ts#L63-L479)
## 详细组件分析
### 连接管理与状态维护
- 连接添加:在连接事件中调用处理器的 add为新连接创建空的连接 ID 集合。
- 连接移除:在关闭事件中调用处理器的 remove清理连接组并广播断开消息。
- 心跳与超时:处理器内置心跳检测(注释掉的 AddHeartbeat/RemoveHeartbeat通过 ping/pong 维护 lastActivity超时触发断开。
```mermaid
flowchart TD
Start(["连接事件"]) --> Add["add(ws)<br/>创建连接ID集合"]
Add --> Role["onConnect(ws, connectionId)<br/>分配角色/生成participantId"]
Role --> Group{"是否已有连接组?"}
Group --> |否| Host["创建连接组(host=ws)"]
Group --> |是| Join["加入现有连接组(participants)"]
Host --> Notify["通知客户端 connect(含 role/polite/participantId)"]
Join --> Notify
Notify --> Msg["等待消息: offer/answer/candidate/ping/broadcast"]
Msg --> Ping{"收到 ping?"}
Ping --> |是| Pong["发送 pong 并更新 lastActivity"]
Ping --> |否| Route["按角色与模式路由消息"]
Route --> Close{"连接关闭/超时?"}
Close --> |是| Remove["remove(ws)<br/>清理并广播断开"]
Close --> |否| Msg
```
图表来源
- [websocket.ts:27-115](file://src/websocket.ts#L27-L115)
- [websockethandler.ts:72-206](file://src/class/websockethandler.ts#L72-L206)
- [websockethandler.ts:404-430](file://src/class/websockethandler.ts#L404-L430)
章节来源
- [websocket.ts:27-115](file://src/websocket.ts#L27-L115)
- [websockethandler.ts:72-206](file://src/class/websockethandler.ts#L72-L206)
- [websockethandler.ts:404-430](file://src/class/websockethandler.ts#L404-L430)
### 连接组管理算法(主机与参与者)
- 角色分配:首次 onConnect 的客户端作为 host后续为 participants私有模式下首次连接的 polite=false其余为 true。
- 组内通信规则:
- host 发送的 offer/answer/candidate 转发给所有 participants。
- participants 发送的 offer/answer/candidate 转发给 host。
- 支持按 participantId 精确路由(私有模式下 host 可定向发送给特定 participant
- 断开处理host 离开时广播断开并删除连接组participant 离开时通知 host 并从组中移除。
```mermaid
classDiagram
class ConnectionGroup {
+host : WebSocket
+participants : Set~WebSocket~
}
class Handler {
+connectionGroup : Map~string, ConnectionGroup~
+isPrivate : boolean
+onConnect(ws, connectionId)
+onDisconnect(ws, connectionId)
+onOffer(ws, message)
+onAnswer(ws, message)
+onCandidate(ws, message)
+broadcastToGroup(connectionId, senderWs, message)
}
Handler --> ConnectionGroup : "维护/查询"
```
图表来源
- [websockethandler.ts:27-37](file://src/class/websockethandler.ts#L27-L37)
- [websockethandler.ts:145-206](file://src/class/websockethandler.ts#L145-L206)
- [websockethandler.ts:214-338](file://src/class/websockethandler.ts#L214-L338)
章节来源
- [websockethandler.ts:145-206](file://src/class/websockethandler.ts#L145-L206)
- [websockethandler.ts:214-338](file://src/class/websockethandler.ts#L214-L338)
### Offer/Answer 协商流程WebSocket 实现)
- SDP 交换:处理器将客户端发送的 SDP 封装为 Offer/Answer 对象,附加时间戳与 polite 标记。
- 路由规则:
- 私有模式host 可按 participantId 精确发送 offer/answer否则广播给所有 participants。
- 公共模式:若连接组不存在则创建,随后向所有其他客户端广播 offer。
- 参与者角色participant 发送的 offer/answer 自动路由至 host携带发送者的 participantId 以便 host 识别来源。
```mermaid
sequenceDiagram
participant P1 as "参与者1"
participant P2 as "参与者2"
participant Host as "主机"
participant Handler as "处理器"
P1->>Handler : "onOffer({connectionId,sdp})"
Handler->>Handler : "封装为 Offer 对象"
alt 私有模式
Handler->>P2 : "按 participantId 转发 offer"
Handler->>Host : "转发 offer(含 participantId)"
else 公共模式
Handler->>P2 : "广播 offer"
end
Host->>Handler : "onAnswer({connectionId,sdp,participantId?})"
Handler->>P2 : "按 participantId 转发 answer 或广播"
```
图表来源
- [websockethandler.ts:214-301](file://src/class/websockethandler.ts#L214-L301)
- [offer.ts:1-11](file://src/class/offer.ts#L1-L11)
- [answer.ts:1-8](file://src/class/answer.ts#L1-L8)
章节来源
- [websockethandler.ts:214-301](file://src/class/websockethandler.ts#L214-L301)
- [offer.ts:1-11](file://src/class/offer.ts#L1-L11)
- [answer.ts:1-8](file://src/class/answer.ts#L1-L8)
### ICE 候选者传输Candidate
- 传输机制:与 Offer/Answer 类似,处理器将候选者封装为 Candidate 对象,携带 sdpMid、sdpMLineIndex 与时间戳。
- 路由逻辑:
- 私有模式host 可按 participantId 精确发送;否则广播。
- 公共模式:当前实现未覆盖公共模式下的 Candidate 转发(保留注释的实现位置)。
- 处理器提供按组广播与按角色路由的能力,便于扩展公共模式下的 Candidate 转发。
```mermaid
flowchart TD
A["收到 candidate 消息"] --> B["封装 Candidate 对象"]
B --> C{"私有模式?"}
C --> |是| D["按 participantId 路由或广播"]
C --> |否| E["当前未实现公共模式转发(保留扩展位)"]
D --> F["发送到目标客户端"]
E --> F
```
图表来源
- [websockethandler.ts:309-338](file://src/class/websockethandler.ts#L309-L338)
- [candidate.ts:1-12](file://src/class/candidate.ts#L1-L12)
章节来源
- [websockethandler.ts:309-338](file://src/class/websockethandler.ts#L309-L338)
- [candidate.ts:1-12](file://src/class/candidate.ts#L1-L12)
### 私有模式 vs 公共模式
- 私有模式private
- 连接组隔离:每个 connectionId 对应唯一连接组host 与 participants 明确划分。
- 精确路由:支持按 participantId 精确发送 offer/answer/candidate。
- 断开影响host 离开导致房间解散并广播断开participant 离开仅通知 host。
- 公共模式public
- 广播为主offer 会广播给所有其他客户端answer/candidate 当前未实现广播。
- 角色默认为 participant首次连接的客户端被标记为 participantpolite=true
```mermaid
graph LR
Private["私有模式"] --> P1["连接组隔离"]
Private --> P2["按 participantId 精确路由"]
Private --> P3["host 离开即解散房间"]
Public["公共模式"] --> U1["offer 广播给其他客户端"]
Public --> U2["answer/candidate 当前未广播(保留扩展)"]
Public --> U3["默认 participant 角色"]
```
图表来源
- [websockethandler.ts:150-260](file://src/class/websockethandler.ts#L150-L260)
- [websockethandler.ts:315-338](file://src/class/websockethandler.ts#L315-L338)
章节来源
- [websockethandler.ts:150-260](file://src/class/websockethandler.ts#L150-L260)
- [websockethandler.ts:315-338](file://src/class/websockethandler.ts#L315-L338)
### 心跳检测、超时与连接恢复
- 心跳机制:处理器预留心跳检测(注释掉),通过 ping/pong 维护 lastActivity定时检查超时并触发断开。
- 超时策略:当前实现注释掉,未在运行时启用;建议在生产环境启用以提升鲁棒性。
- 连接恢复:客户端需重新发起 connect 流程,处理器会重新分配角色并重建连接组。
```mermaid
flowchart TD
S["开始计时"] --> T["发送 ping"]
T --> R{"收到 pong?"}
R --> |是| U["更新 lastActivity"]
R --> |否| O{"超时(>阈值)?"}
O --> |是| X["执行断开(onDisconnect)"]
O --> |否| T
```
图表来源
- [websocket.ts:95-100](file://src/websocket.ts#L95-L100)
- [websockethandler.ts:404-430](file://src/class/websockethandler.ts#L404-L430)
章节来源
- [websocket.ts:95-100](file://src/websocket.ts#L95-L100)
- [websockethandler.ts:404-430](file://src/class/websockethandler.ts#L404-L430)
### 广播与消息路由
- 组内广播:处理器提供 broadcastToGrouphost 向所有 participants 转发participants 向 host 转发。
- 全局广播onBroadcast 支持向指定连接组或全局广播消息。
- 聊天消息onMessage 将 host 的消息广播给 participantsparticipant 的消息转发给 host 并同步给其他 participants。
章节来源
- [websockethandler.ts:97-109](file://src/class/websockethandler.ts#L97-L109)
- [websockethandler.ts:370-402](file://src/class/websockethandler.ts#L370-L402)
- [websockethandler.ts:448-473](file://src/class/websockethandler.ts#L448-L473)
### 与 HTTP 信令的对比(概念性说明)
- HTTP 信令通过轮询获取 offer/answer/candidate适合无法使用 WebSocket 的场景。
- 数据持久化HTTP 处理器将信令消息存储在内存映射中,支持按会话与时间过滤查询。
- 适用场景:弱网环境、代理限制、或需要与传统系统集成的场景。
章节来源
- [signaling.ts:1-25](file://src/signaling.ts#L1-L25)
- [httphandler.ts:1-800](file://src/class/httphandler.ts#L1-L800)
## 依赖关系分析
- 入口依赖index.ts 依赖 server.ts 创建 HTTP 服务,再由 server.ts 注册 /signaling 路由与静态资源。
- WebSocket 依赖websocket.ts 依赖 websockethandler.ts 进行连接与消息处理;依赖 log.ts 输出日志。
- 数据模型依赖websockethandler.ts 依赖 offer.ts/answer.ts/candidate.ts 封装 SDP 与候选者。
- 配置依赖index.ts 与 server.ts 读取 options.ts 的运行参数package.json 提供依赖与脚本。
```mermaid
graph TB
Index["index.ts"] --> Server["server.ts"]
Server --> WS["websocket.ts"]
WS --> Handler["websockethandler.ts"]
Handler --> ModelO["offer.ts"]
Handler --> ModelA["answer.ts"]
Handler --> ModelC["candidate.ts"]
WS --> Log["log.ts"]
Index --> Opt["options.ts"]
Server --> Signaling["signaling.ts"]
Signaling --> HttpH["httphandler.ts"]
```
图表来源
- [index.ts:52-91](file://src/index.ts#L52-L91)
- [server.ts:14-42](file://src/server.ts#L14-L42)
- [websocket.ts:6-117](file://src/websocket.ts#L6-L117)
- [websockethandler.ts:1-479](file://src/class/websockethandler.ts#L1-L479)
- [offer.ts:1-11](file://src/class/offer.ts#L1-L11)
- [answer.ts:1-8](file://src/class/answer.ts#L1-L8)
- [candidate.ts:1-12](file://src/class/candidate.ts#L1-L12)
- [log.ts:1-51](file://src/log.ts#L1-L51)
- [options.ts:1-10](file://src/class/options.ts#L1-L10)
- [signaling.ts:1-25](file://src/signaling.ts#L1-L25)
- [httphandler.ts:1-800](file://src/class/httphandler.ts#L1-L800)
章节来源
- [index.ts:52-91](file://src/index.ts#L52-L91)
- [server.ts:14-42](file://src/server.ts#L14-L42)
- [websocket.ts:6-117](file://src/websocket.ts#L6-L117)
- [websockethandler.ts:1-479](file://src/class/websockethandler.ts#L1-L479)
- [signaling.ts:1-25](file://src/signaling.ts#L1-L25)
- [httphandler.ts:1-800](file://src/class/httphandler.ts#L1-L800)
## 性能考量
- 内存占用:连接组与消息对象均使用 Map/Set 存储,复杂度与连接数线性相关。
- 路由效率:广播与按角色路由均为 O(n) 遍历,适合中小规模并发。
- 建议优化:
- 使用连接池与连接复用,避免频繁创建/销毁。
- 对广播消息进行去重与合并,降低网络负载。
- 引入心跳与超时(启用注释的实现)以及时回收无效连接。
## 故障排查指南
- 连接无法建立:
- 检查服务端启动参数与证书配置确认端口与协议HTTP/HTTPS正确。
- 查看日志输出,定位 onConnect/添加连接阶段的问题。
- 消息未到达:
- 确认连接组存在且角色正确;核对 participantId 与 connectionId。
- 检查私有/公共模式下的路由分支是否符合预期。
- 心跳与超时:
- 若启用心跳,确认 ping/pong 循环正常;检查 lastActivity 更新。
- 未启用心跳时,长时间无活动可能导致连接被断开。
- 单元测试参考:
- 使用测试用例验证公有/私有模式下的连接、Offer/Answer、Candidate 路由行为。
章节来源
- [log.ts:30-50](file://src/log.ts#L30-L50)
- [websockethandler.test.ts:1-191](file://test/websockethandler.test.ts#L1-L191)
## 结论
WebSocket 信令处理器通过清晰的连接组模型与角色路由,实现了灵活的多方通信能力。私有模式强调精确路由与房间隔离,公共模式强调广播与易用性。结合心跳与超时机制,系统具备较好的稳定性与可维护性。未来可在公共模式下完善 Candidate 转发与心跳启用,进一步提升可用性与健壮性。
## 附录
### WebSocket 信令流程示例(私有模式)
- 步骤 1客户端 A 连接,成为 hostpolite=false
- 步骤 2客户端 B 连接,成为 participantpolite=true
- 步骤 3B 发送 offer处理器转发给 A。
- 步骤 4A 回答 answer处理器按 participantId 转发给 B。
- 步骤 5双方交换 ICE 候选者,处理器按 participantId 转发。
- 步骤 6任一方断开处理器广播断开并清理连接组。
章节来源
- [websockethandler.ts:145-206](file://src/class/websockethandler.ts#L145-L206)
- [websockethandler.ts:214-301](file://src/class/websockethandler.ts#L214-L301)
- [websockethandler.ts:309-338](file://src/class/websockethandler.ts#L309-L338)
### 调试技巧
- 启用详细日志:通过日志级别控制输出,定位连接、路由与广播问题。
- 使用测试工具:参考单元测试用例,模拟公有/私有模式下的行为。
- 关注客户端文档OneByOne 客户端 README 描述了 WebSocket 事件与心跳机制,有助于理解客户端侧的配合。
章节来源
- [log.ts:15-24](file://src/log.ts#L15-L24)
- [websockethandler.test.ts:1-191](file://test/websockethandler.test.ts#L1-L191)
- [README.md:126-136](file://client/public/onebyone/README.md#L126-L136)