447 lines
21 KiB
Markdown
447 lines
21 KiB
Markdown
|
|
# 信令系统
|
|||
|
|
|
|||
|
|
<cite>
|
|||
|
|
**本文引用的文件**
|
|||
|
|
- [src/index.ts](file://src/index.ts)
|
|||
|
|
- [src/server.ts](file://src/server.ts)
|
|||
|
|
- [src/signaling.ts](file://src/signaling.ts)
|
|||
|
|
- [src/websocket.ts](file://src/websocket.ts)
|
|||
|
|
- [src/class/websockethandler.ts](file://src/class/websockethandler.ts)
|
|||
|
|
- [src/class/httphandler.ts](file://src/class/httphandler.ts)
|
|||
|
|
- [src/class/offer.ts](file://src/class/offer.ts)
|
|||
|
|
- [src/class/answer.ts](file://src/class/answer.ts)
|
|||
|
|
- [src/class/candidate.ts](file://src/class/candidate.ts)
|
|||
|
|
- [src/class/options.ts](file://src/class/options.ts)
|
|||
|
|
- [src/log.ts](file://src/log.ts)
|
|||
|
|
- [src/服务端接口与WebSocket消息类型.md](file://src/服务端接口与WebSocket消息类型.md)
|
|||
|
|
- [test/websockethandler.test.ts](file://test/websockethandler.test.ts)
|
|||
|
|
- [test/httphandler.test.ts](file://test/httphandler.test.ts)
|
|||
|
|
- [package.json](file://package.json)
|
|||
|
|
</cite>
|
|||
|
|
|
|||
|
|
## 目录
|
|||
|
|
1. [简介](#简介)
|
|||
|
|
2. [项目结构](#项目结构)
|
|||
|
|
3. [核心组件](#核心组件)
|
|||
|
|
4. [架构总览](#架构总览)
|
|||
|
|
5. [详细组件分析](#详细组件分析)
|
|||
|
|
6. [依赖关系分析](#依赖关系分析)
|
|||
|
|
7. [性能考虑](#性能考虑)
|
|||
|
|
8. [故障排查指南](#故障排查指南)
|
|||
|
|
9. [结论](#结论)
|
|||
|
|
10. [附录](#附录)
|
|||
|
|
|
|||
|
|
## 简介
|
|||
|
|
本项目是一个支持 HTTP 轮询与 WebSocket 双协议的 WebRTC 信令服务器,提供 Offer/Answer SDP 协商与 ICE 候选者交换能力,并内置公共模式与私有模式两种通信拓扑。系统通过会话(Session)与连接(Connection)抽象实现消息隔离与路由,支持增量拉取、心跳检测与房间广播等特性。
|
|||
|
|
|
|||
|
|
## 项目结构
|
|||
|
|
- 服务启动与配置:应用入口负责解析命令行参数、创建 HTTP/HTTPS 服务器、选择信令协议与通信模式,并初始化 WebSocket 信令服务。
|
|||
|
|
- 服务器装配:Express 应用注册日志中间件、CORS、静态资源、Swagger 文档,并挂载 /signaling 路由。
|
|||
|
|
- 信令路由:HTTP 路由统一转发至 HTTP 处理器;WebSocket 服务器监听连接事件并分派消息到 WebSocket 处理器。
|
|||
|
|
- 数据模型:Offer/Answer/Candidate 作为不可变数据载体,承载 SDP 与 ICE 候选者元数据。
|
|||
|
|
- 测试与文档:配套单元测试覆盖公共/私有模式行为与会话超时清理;Markdown 提供完整接口与消息类型规范。
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
graph TB
|
|||
|
|
A["应用入口<br/>src/index.ts"] --> B["Express 服务器<br/>src/server.ts"]
|
|||
|
|
B --> C["HTTP 路由<br/>src/signaling.ts"]
|
|||
|
|
B --> D["WebSocket 服务器<br/>src/websocket.ts"]
|
|||
|
|
C --> E["HTTP 处理器<br/>src/class/httphandler.ts"]
|
|||
|
|
D --> F["WebSocket 处理器<br/>src/class/websockethandler.ts"]
|
|||
|
|
E --> G["数据模型<br/>offer.ts / answer.ts / candidate.ts"]
|
|||
|
|
F --> G
|
|||
|
|
A --> H["日志工具<br/>src/log.ts"]
|
|||
|
|
A --> I["配置选项<br/>src/class/options.ts"]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**图表来源**
|
|||
|
|
- [src/index.ts:1-109](file://src/index.ts#L1-L109)
|
|||
|
|
- [src/server.ts:14-89](file://src/server.ts#L14-L89)
|
|||
|
|
- [src/signaling.ts:1-25](file://src/signaling.ts#L1-L25)
|
|||
|
|
- [src/websocket.ts:1-118](file://src/websocket.ts#L1-L118)
|
|||
|
|
- [src/class/httphandler.ts:1-120](file://src/class/httphandler.ts#L1-L120)
|
|||
|
|
- [src/class/websockethandler.ts:1-66](file://src/class/websockethandler.ts#L1-L66)
|
|||
|
|
- [src/class/offer.ts:1-11](file://src/class/offer.ts#L1-L11)
|
|||
|
|
- [src/class/answer.ts:1-8](file://src/class/answer.ts#L1-L8)
|
|||
|
|
- [src/class/candidate.ts:1-12](file://src/class/candidate.ts#L1-L12)
|
|||
|
|
- [src/log.ts:1-51](file://src/log.ts#L1-L51)
|
|||
|
|
- [src/class/options.ts:1-10](file://src/class/options.ts#L1-L10)
|
|||
|
|
|
|||
|
|
**章节来源**
|
|||
|
|
- [src/index.ts:13-109](file://src/index.ts#L13-L109)
|
|||
|
|
- [src/server.ts:14-89](file://src/server.ts#L14-L89)
|
|||
|
|
- [src/signaling.ts:1-25](file://src/signaling.ts#L1-L25)
|
|||
|
|
- [src/websocket.ts:6-118](file://src/websocket.ts#L6-L118)
|
|||
|
|
- [src/class/httphandler.ts:1-120](file://src/class/httphandler.ts#L1-L120)
|
|||
|
|
- [src/class/websockethandler.ts:1-66](file://src/class/websockethandler.ts#L1-L66)
|
|||
|
|
|
|||
|
|
## 核心组件
|
|||
|
|
- 应用入口与配置
|
|||
|
|
- 解析端口、HTTPS、协议类型(websocket/http)、通信模式(public/private)、日志级别等参数。
|
|||
|
|
- 根据配置创建 HTTP/HTTPS 服务器,并在 websocket 模式下初始化 WebSocket 信令服务。
|
|||
|
|
- Express 服务器
|
|||
|
|
- 注册 Morgan 日志、CORS、JSON/URL 编码中间件。
|
|||
|
|
- 提供 /config、/signaling 路由、静态资源与 Swagger 文档。
|
|||
|
|
- HTTP 信令处理器
|
|||
|
|
- 会话管理:创建/删除会话、检查会话 ID、超时清理。
|
|||
|
|
- 连接管理:创建/删除连接、维护连接对映射。
|
|||
|
|
- SDP 与 ICE:存储 offer/answer/candidate,按模式进行路由与过滤。
|
|||
|
|
- 增量拉取:支持 fromtime 参数按时间窗口获取消息。
|
|||
|
|
- WebSocket 信令处理器
|
|||
|
|
- 会话与连接组:支持公共模式全连通与私有模式 1 对多房间。
|
|||
|
|
- 消息路由:connect/disconnect/offer/answer/candidate/broadcast/on-message/call-request/ping/pong。
|
|||
|
|
- 心跳检测:可选的 ping/pong 心跳(默认未启用)。
|
|||
|
|
- 数据模型
|
|||
|
|
- Offer:SDP、时间戳、polite 标志。
|
|||
|
|
- Answer:SDP、时间戳。
|
|||
|
|
- Candidate:ICE 候选者字符串、sdpMLineIndex、sdpMid、时间戳。
|
|||
|
|
|
|||
|
|
**章节来源**
|
|||
|
|
- [src/index.ts:14-109](file://src/index.ts#L14-L109)
|
|||
|
|
- [src/server.ts:14-89](file://src/server.ts#L14-L89)
|
|||
|
|
- [src/class/httphandler.ts:31-120](file://src/class/httphandler.ts#L31-L120)
|
|||
|
|
- [src/class/websockethandler.ts:10-66](file://src/class/websockethandler.ts#L10-L66)
|
|||
|
|
- [src/class/offer.ts:1-11](file://src/class/offer.ts#L1-L11)
|
|||
|
|
- [src/class/answer.ts:1-8](file://src/class/answer.ts#L1-L8)
|
|||
|
|
- [src/class/candidate.ts:1-12](file://src/class/candidate.ts#L1-L12)
|
|||
|
|
|
|||
|
|
## 架构总览
|
|||
|
|
系统采用“协议无关”的信令处理层设计:HTTP 与 WebSocket 分别通过各自的处理器对接同一套业务逻辑与数据模型,从而实现公共/私有模式的统一语义。
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
graph TB
|
|||
|
|
subgraph "客户端"
|
|||
|
|
WS["WebSocket 客户端"]
|
|||
|
|
HTTP["HTTP 客户端"]
|
|||
|
|
end
|
|||
|
|
subgraph "服务器"
|
|||
|
|
Srv["Express 服务器"]
|
|||
|
|
WSrv["WebSocket 服务器"]
|
|||
|
|
HR["HTTP 处理器"]
|
|||
|
|
WR["WebSocket 处理器"]
|
|||
|
|
DM["数据模型"]
|
|||
|
|
end
|
|||
|
|
WS --> WSrv --> WR
|
|||
|
|
HTTP --> Srv --> HR
|
|||
|
|
WR --> DM
|
|||
|
|
HR --> DM
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**图表来源**
|
|||
|
|
- [src/server.ts:14-29](file://src/server.ts#L14-L29)
|
|||
|
|
- [src/websocket.ts:15-118](file://src/websocket.ts#L15-L118)
|
|||
|
|
- [src/class/httphandler.ts:107-120](file://src/class/httphandler.ts#L107-L120)
|
|||
|
|
- [src/class/websockethandler.ts:63-66](file://src/class/websockethandler.ts#L63-L66)
|
|||
|
|
|
|||
|
|
## 详细组件分析
|
|||
|
|
|
|||
|
|
### WebSocket 信令处理器
|
|||
|
|
- 会话与连接组
|
|||
|
|
- 使用 Map<WebSocket, Set<string>> 维护每个连接的连接 ID 集合。
|
|||
|
|
- 使用 Map<string, ConnectionGroup> 维护连接组:host 与 participants。
|
|||
|
|
- 模式差异
|
|||
|
|
- 公共模式:任意客户端可向其他所有客户端广播消息。
|
|||
|
|
- 私有模式:host 与 participants 之间双向路由,支持单播/广播。
|
|||
|
|
- 关键消息处理
|
|||
|
|
- connect/disconnect:建立/断开连接,维护连接组与角色(host/participant)。
|
|||
|
|
- offer/answer/candidate:根据模式与 participantId 进行路由。
|
|||
|
|
- broadcast/on-message:组内广播与点对点消息传递。
|
|||
|
|
- ping/pong:心跳检测(可选)。
|
|||
|
|
- 广播与路由
|
|||
|
|
- host → 所有 participants;participant → host。
|
|||
|
|
- 私有模式支持按 participantId 单播。
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
sequenceDiagram
|
|||
|
|
participant C1 as "客户端1"
|
|||
|
|
participant C2 as "客户端2"
|
|||
|
|
participant WS as "WebSocket服务器"
|
|||
|
|
participant WH as "WebSocket处理器"
|
|||
|
|
C1->>WS : "connect {connectionId}"
|
|||
|
|
WS->>WH : "onConnect(ws, connectionId)"
|
|||
|
|
WH-->>C1 : "{type : 'connect', polite : false, role : 'host', participantId}"
|
|||
|
|
C2->>WS : "connect {connectionId}"
|
|||
|
|
WS->>WH : "onConnect(ws, connectionId)"
|
|||
|
|
WH-->>C2 : "{type : 'connect', polite : true, role : 'participant', participantId}"
|
|||
|
|
C1->>WS : "offer {connectionId, sdp}"
|
|||
|
|
WS->>WH : "onOffer(ws, data)"
|
|||
|
|
WH-->>C2 : "{type : 'offer', data : {sdp, connectionId, participantId}, participantId}"
|
|||
|
|
C2->>WS : "answer {connectionId, sdp}"
|
|||
|
|
WS->>WH : "onAnswer(ws, data)"
|
|||
|
|
WH-->>C1 : "{type : 'answer', data : {sdp, connectionId, participantId}, participantId}"
|
|||
|
|
C1->>WS : "candidate {connectionId, candidate, sdpMLineIndex, sdpMid}"
|
|||
|
|
WS->>WH : "onCandidate(ws, data)"
|
|||
|
|
WH-->>C2 : "{type : 'candidate', data : {candidate, sdpMLineIndex, sdpMid, connectionId, participantId}, participantId}"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**图表来源**
|
|||
|
|
- [src/websocket.ts:27-115](file://src/websocket.ts#L27-L115)
|
|||
|
|
- [src/class/websockethandler.ts:145-338](file://src/class/websockethandler.ts#L145-L338)
|
|||
|
|
|
|||
|
|
**章节来源**
|
|||
|
|
- [src/class/websockethandler.ts:139-338](file://src/class/websockethandler.ts#L139-L338)
|
|||
|
|
- [src/websocket.ts:15-118](file://src/websocket.ts#L15-L118)
|
|||
|
|
|
|||
|
|
### HTTP 信令处理器
|
|||
|
|
- 会话与连接
|
|||
|
|
- 会话 ID 通过请求头 Session-Id 传递;处理器内部维护 clients、connectionPair、offers、answers、candidates、disconnections 映射。
|
|||
|
|
- 私有模式下通过 connectionPair 实现 1 对 1 或 1 对多配对。
|
|||
|
|
- 超时与清理
|
|||
|
|
- lastRequestedTime 记录会话最后请求时间;超过阈值(10 秒)自动清理会话及其关联资源。
|
|||
|
|
- SDP 与 ICE
|
|||
|
|
- postOffer/postAnswer/postCandidate 存储消息;getOffer/getAnswer/getCandidate 支持 fromtime 增量拉取。
|
|||
|
|
- answer 到来时更新对应连接的 candidate 时间戳,确保时序一致性。
|
|||
|
|
- 房间与连接 ID
|
|||
|
|
- 提供 /rooms、/connection-ids 等辅助接口,便于监控与调试。
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
flowchart TD
|
|||
|
|
Start(["HTTP 请求进入"]) --> CheckSession["校验 Session-Id"]
|
|||
|
|
CheckSession --> Route{"路由到哪类操作?"}
|
|||
|
|
Route --> |创建会话| CreateSession["PUT / -> createSession"]
|
|||
|
|
Route --> |删除会话| DeleteSession["DELETE / -> deleteSession"]
|
|||
|
|
Route --> |创建连接| CreateConn["PUT /connection -> createConnection"]
|
|||
|
|
Route --> |删除连接| DeleteConn["DELETE /connection -> deleteConnection"]
|
|||
|
|
Route --> |发送SDP| PostMsg["POST /offer|answer|candidate -> 存储消息"]
|
|||
|
|
Route --> |拉取消息| GetMsg["GET /offer|answer|candidate| -> 增量返回"]
|
|||
|
|
CreateSession --> End(["返回 sessionId"])
|
|||
|
|
DeleteSession --> End
|
|||
|
|
CreateConn --> End
|
|||
|
|
DeleteConn --> End
|
|||
|
|
PostMsg --> End
|
|||
|
|
GetMsg --> End
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**图表来源**
|
|||
|
|
- [src/class/httphandler.ts:128-145](file://src/class/httphandler.ts#L128-L145)
|
|||
|
|
- [src/class/httphandler.ts:661-696](file://src/class/httphandler.ts#L661-L696)
|
|||
|
|
- [src/class/httphandler.ts:739-783](file://src/class/httphandler.ts#L739-L783)
|
|||
|
|
- [src/class/httphandler.ts:815-828](file://src/class/httphandler.ts#L815-L828)
|
|||
|
|
- [src/class/httphandler.ts:855-886](file://src/class/httphandler.ts#L855-L886)
|
|||
|
|
- [src/class/httphandler.ts:913-952](file://src/class/httphandler.ts#L913-L952)
|
|||
|
|
- [src/class/httphandler.ts:985-998](file://src/class/httphandler.ts#L985-L998)
|
|||
|
|
|
|||
|
|
**章节来源**
|
|||
|
|
- [src/class/httphandler.ts:128-145](file://src/class/httphandler.ts#L128-L145)
|
|||
|
|
- [src/class/httphandler.ts:218-232](file://src/class/httphandler.ts#L218-L232)
|
|||
|
|
- [src/class/httphandler.ts:274-297](file://src/class/httphandler.ts#L274-L297)
|
|||
|
|
- [src/class/httphandler.ts:305-318](file://src/class/httphandler.ts#L305-L318)
|
|||
|
|
- [src/class/httphandler.ts:326-356](file://src/class/httphandler.ts#L326-L356)
|
|||
|
|
- [src/class/httphandler.ts:661-696](file://src/class/httphandler.ts#L661-L696)
|
|||
|
|
- [src/class/httphandler.ts:739-783](file://src/class/httphandler.ts#L739-L783)
|
|||
|
|
- [src/class/httphandler.ts:815-828](file://src/class/httphandler.ts#L815-L828)
|
|||
|
|
- [src/class/httphandler.ts:855-886](file://src/class/httphandler.ts#L855-L886)
|
|||
|
|
- [src/class/httphandler.ts:913-952](file://src/class/httphandler.ts#L913-L952)
|
|||
|
|
- [src/class/httphandler.ts:985-998](file://src/class/httphandler.ts#L985-L998)
|
|||
|
|
|
|||
|
|
### Offer/Answer SDP 协商与 ICE 候选者交换
|
|||
|
|
- Offer/Answer
|
|||
|
|
- 公共模式:Peer → 所有其他 Peers。
|
|||
|
|
- 私有模式:Host ↔ Participants;Host 可单播给特定 participant 或广播给所有 participants。
|
|||
|
|
- Candidate
|
|||
|
|
- 与 answer 路由规则一致,支持按 participantId 单播。
|
|||
|
|
- Polite 标志
|
|||
|
|
- 私有模式下:host 为 `polite=false`,participants 为 `polite=true`,避免并发 offer 冲突。
|
|||
|
|
- 增量拉取
|
|||
|
|
- HTTP 模式支持 fromtime 参数,客户端可增量获取消息,减少网络与存储压力。
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
sequenceDiagram
|
|||
|
|
participant P1 as "参与者1"
|
|||
|
|
participant P2 as "参与者2"
|
|||
|
|
participant S as "信令服务器"
|
|||
|
|
P1->>S : "POST /signaling/offer {connectionId, sdp}"
|
|||
|
|
S-->>P2 : "GET /signaling/offer?fromtime=... -> {offers : [{connectionId,sdp,polite,...}]}"
|
|||
|
|
P2->>S : "POST /signaling/answer {connectionId, sdp}"
|
|||
|
|
S-->>P1 : "GET /signaling/answer?fromtime=... -> {answers : [{connectionId,sdp,...}]}"
|
|||
|
|
loop "ICE 候选者收集"
|
|||
|
|
P1->>S : "POST /signaling/candidate {connectionId, candidate, sdpMLineIndex, sdpMid}"
|
|||
|
|
S-->>P2 : "GET /signaling/candidate?fromtime=... -> {candidates : [{connectionId,candidate,sdpMLineIndex,sdpMid,...}]}"
|
|||
|
|
P2->>S : "POST /signaling/candidate {connectionId, candidate, sdpMLineIndex, sdpMid}"
|
|||
|
|
S-->>P1 : "GET /signaling/candidate?fromtime=... -> {candidates : [{connectionId,candidate,sdpMLineIndex,sdpMid,...}]}"
|
|||
|
|
end
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**图表来源**
|
|||
|
|
- [src/class/httphandler.ts:274-297](file://src/class/httphandler.ts#L274-L297)
|
|||
|
|
- [src/class/httphandler.ts:305-318](file://src/class/httphandler.ts#L305-L318)
|
|||
|
|
- [src/class/httphandler.ts:326-356](file://src/class/httphandler.ts#L326-L356)
|
|||
|
|
- [src/class/httphandler.ts:855-886](file://src/class/httphandler.ts#L855-L886)
|
|||
|
|
- [src/class/httphandler.ts:913-952](file://src/class/httphandler.ts#L913-L952)
|
|||
|
|
- [src/class/httphandler.ts:985-998](file://src/class/httphandler.ts#L985-L998)
|
|||
|
|
|
|||
|
|
**章节来源**
|
|||
|
|
- [src/class/httphandler.ts:274-356](file://src/class/httphandler.ts#L274-L356)
|
|||
|
|
- [src/class/httphandler.ts:855-998](file://src/class/httphandler.ts#L855-L998)
|
|||
|
|
|
|||
|
|
### 连接组管理机制(公共模式 vs 私有模式)
|
|||
|
|
- 公共模式
|
|||
|
|
- 任意客户端可向其他所有客户端广播消息。
|
|||
|
|
- 适合全连通场景,消息广播范围广但复杂度低。
|
|||
|
|
- 私有模式
|
|||
|
|
- 以 connectionId 为房间标识,host 与 participants 之间双向路由。
|
|||
|
|
- 支持单播与广播;host 离开房间即解散,participant 离开房间保留。
|
|||
|
|
- 通过 participantId 区分发送者身份,便于路由与 UI 展示。
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
classDiagram
|
|||
|
|
class WebSocket处理器 {
|
|||
|
|
+reset(mode)
|
|||
|
|
+add(ws)
|
|||
|
|
+remove(ws)
|
|||
|
|
+onConnect(ws, connectionId)
|
|||
|
|
+onDisconnect(ws, connectionId)
|
|||
|
|
+onOffer(ws, message)
|
|||
|
|
+onAnswer(ws, message)
|
|||
|
|
+onCandidate(ws, message)
|
|||
|
|
+onBroadcast(ws, message)
|
|||
|
|
+onMessage(ws, message)
|
|||
|
|
}
|
|||
|
|
class 连接组 {
|
|||
|
|
+host : WebSocket
|
|||
|
|
+participants : Set~WebSocket~
|
|||
|
|
}
|
|||
|
|
WebSocket处理器 --> 连接组 : "维护/路由"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**图表来源**
|
|||
|
|
- [src/class/websockethandler.ts:63-66](file://src/class/websockethandler.ts#L63-L66)
|
|||
|
|
- [src/class/websockethandler.ts:27-37](file://src/class/websockethandler.ts#L27-L37)
|
|||
|
|
|
|||
|
|
**章节来源**
|
|||
|
|
- [src/class/websockethandler.ts:139-338](file://src/class/websockethandler.ts#L139-L338)
|
|||
|
|
|
|||
|
|
### 信令消息格式规范
|
|||
|
|
- HTTP REST API
|
|||
|
|
- /signaling、/signaling/offer、/signaling/answer、/signaling/candidate、/signaling/connection、/signaling/connection-ids、/signaling/rooms 等接口的请求与响应结构详见接口文档。
|
|||
|
|
- WebSocket 消息类型
|
|||
|
|
- connect/disconnect/participant-joined/participant-left:连接生命周期消息。
|
|||
|
|
- offer/answer/candidate:SDP 与 ICE 候选者消息,支持 participantId 与单播路由。
|
|||
|
|
- on-message:通用消息传递,支持文本/对象。
|
|||
|
|
- broadcast:组内广播或全局广播。
|
|||
|
|
- call-request:发起呼叫请求。
|
|||
|
|
- ping/pong:心跳检测(可选)。
|
|||
|
|
|
|||
|
|
**章节来源**
|
|||
|
|
- [src/服务端接口与WebSocket消息类型.md:35-260](file://src/服务端接口与WebSocket消息类型.md#L35-L260)
|
|||
|
|
- [src/服务端接口与WebSocket消息类型.md:262-487](file://src/服务端接口与WebSocket消息类型.md#L262-L487)
|
|||
|
|
|
|||
|
|
### 错误处理策略与重连机制
|
|||
|
|
- 会话超时
|
|||
|
|
- HTTP 模式下,若 10 秒内无请求,自动清理会话及其资源,避免内存泄漏。
|
|||
|
|
- 会话校验
|
|||
|
|
- HTTP 路由中间件检查 Session-Id,不存在则返回 404。
|
|||
|
|
- 私有模式约束
|
|||
|
|
- 连接 ID 在私有模式下需唯一配对;重复使用会返回 400。
|
|||
|
|
- 重连建议
|
|||
|
|
- 客户端应在断开后重新创建会话(HTTP)或重新建立 WebSocket 连接(WebSocket),并再次执行 connect 流程。
|
|||
|
|
- 增量拉取 fromtime 可帮助客户端恢复丢失的消息。
|
|||
|
|
|
|||
|
|
**章节来源**
|
|||
|
|
- [src/class/httphandler.ts:218-232](file://src/class/httphandler.ts#L218-L232)
|
|||
|
|
- [src/class/httphandler.ts:128-145](file://src/class/httphandler.ts#L128-L145)
|
|||
|
|
- [src/class/httphandler.ts:362-368](file://src/class/httphandler.ts#L362-L368)
|
|||
|
|
|
|||
|
|
### 实际信令流程示例与调试技巧
|
|||
|
|
- 公共模式典型流程
|
|||
|
|
- 客户端 A/B 同时 connect 同一 connectionId,服务器广播 offer/answer/candidate。
|
|||
|
|
- 增量拉取 fromtime 可避免重复处理。
|
|||
|
|
- 私有模式典型流程
|
|||
|
|
- 客户端 A 作为 host,B/C 作为 participants;A 发送 offer 给 B,B 回答后 A 再发送 answer 给 B;ICE 候选者双向交换。
|
|||
|
|
- 调试技巧
|
|||
|
|
- 使用 /config 检查服务器配置(是否启用 WebSocket、启动模式、日志级别)。
|
|||
|
|
- 使用 /signaling/connection-ids 查看活跃连接 ID。
|
|||
|
|
- 使用 /signaling/rooms 查看房间与用户状态。
|
|||
|
|
- 使用 /signaling?fromtime=... 增量拉取消息,定位异常时间窗。
|
|||
|
|
- 开启更详细日志级别以观察消息流转。
|
|||
|
|
|
|||
|
|
**章节来源**
|
|||
|
|
- [src/server.ts:25-41](file://src/server.ts#L25-L41)
|
|||
|
|
- [src/class/httphandler.ts:1041-1076](file://src/class/httphandler.ts#L1041-L1076)
|
|||
|
|
- [src/class/httphandler.ts:1103-1108](file://src/class/httphandler.ts#L1103-L1108)
|
|||
|
|
- [src/服务端接口与WebSocket消息类型.md:508-542](file://src/服务端接口与WebSocket消息类型.md#L508-L542)
|
|||
|
|
|
|||
|
|
## 依赖关系分析
|
|||
|
|
- 外部依赖
|
|||
|
|
- Express、ws、cors、morgan、multer、uuid、swagger 等。
|
|||
|
|
- 内部模块
|
|||
|
|
- index.ts 依赖 server.ts、websocket.ts、websockethandler.ts、httphandler.ts。
|
|||
|
|
- server.ts 依赖 signaling.ts、httphandler.ts。
|
|||
|
|
- signaling.ts 依赖 httphandler.ts。
|
|||
|
|
- websockethandler.ts 依赖 offer.ts、answer.ts、candidate.ts、log.ts。
|
|||
|
|
- httphandler.ts 依赖 offer.ts、answer.ts、candidate.ts、log.ts。
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
graph LR
|
|||
|
|
IDX["index.ts"] --> SRV["server.ts"]
|
|||
|
|
IDX --> WSS["websocket.ts"]
|
|||
|
|
SRV --> SIG["signaling.ts"]
|
|||
|
|
SIG --> HTH["httphandler.ts"]
|
|||
|
|
WSS --> WSH["websockethandler.ts"]
|
|||
|
|
WSH --> OFF["offer.ts"]
|
|||
|
|
WSH --> ANS["answer.ts"]
|
|||
|
|
WSH --> CAN["candidate.ts"]
|
|||
|
|
HTH --> OFF
|
|||
|
|
HTH --> ANS
|
|||
|
|
HTH --> CAN
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**图表来源**
|
|||
|
|
- [src/index.ts:7-10](file://src/index.ts#L7-L10)
|
|||
|
|
- [src/server.ts:1-12](file://src/server.ts#L1-L12)
|
|||
|
|
- [src/signaling.ts:1-3](file://src/signaling.ts#L1-L3)
|
|||
|
|
- [src/websocket.ts:1-4](file://src/websocket.ts#L1-L4)
|
|||
|
|
- [src/class/websockethandler.ts:5-8](file://src/class/websockethandler.ts#L5-L8)
|
|||
|
|
- [src/class/httphandler.ts:5-11](file://src/class/httphandler.ts#L5-L11)
|
|||
|
|
|
|||
|
|
**章节来源**
|
|||
|
|
- [package.json:14-27](file://package.json#L14-L27)
|
|||
|
|
- [src/index.ts:1-12](file://src/index.ts#L1-L12)
|
|||
|
|
- [src/server.ts:1-12](file://src/server.ts#L1-L12)
|
|||
|
|
- [src/signaling.ts:1-3](file://src/signaling.ts#L1-L3)
|
|||
|
|
- [src/websocket.ts:1-4](file://src/websocket.ts#L1-L4)
|
|||
|
|
- [src/class/websockethandler.ts:5-8](file://src/class/websockethandler.ts#L5-L8)
|
|||
|
|
- [src/class/httphandler.ts:5-11](file://src/class/httphandler.ts#L5-L11)
|
|||
|
|
|
|||
|
|
## 性能考虑
|
|||
|
|
- HTTP 轮询
|
|||
|
|
- fromtime 增量拉取减少无效数据传输。
|
|||
|
|
- 会话超时清理避免长期占用内存。
|
|||
|
|
- WebSocket
|
|||
|
|
- 按组广播与单播路由降低广播风暴。
|
|||
|
|
- 可选心跳检测防止长连接空闲断开。
|
|||
|
|
- 存储与序列化
|
|||
|
|
- 使用轻量级对象承载 SDP 与 ICE 元数据,避免冗余字段。
|
|||
|
|
- 建议客户端侧缓存最近消息,减少重复请求。
|
|||
|
|
|
|||
|
|
## 故障排查指南
|
|||
|
|
- 无法获取会话
|
|||
|
|
- 确认请求头是否包含正确的 Session-Id。
|
|||
|
|
- 检查会话是否因超时被清理。
|
|||
|
|
- 私有模式连接冲突
|
|||
|
|
- 确认 connectionId 未被重复使用。
|
|||
|
|
- 检查 host/participant 角色与 polite 标志。
|
|||
|
|
- 消息未到达
|
|||
|
|
- 使用 /signaling?fromtime=... 增量拉取确认消息是否已存储。
|
|||
|
|
- 检查模式配置(public/private)与路由规则。
|
|||
|
|
- 日志与监控
|
|||
|
|
- 提升日志级别以观察消息流转。
|
|||
|
|
- 使用 /signaling/rooms 与 /signaling/connection-ids 快速定位问题。
|
|||
|
|
|
|||
|
|
**章节来源**
|
|||
|
|
- [src/class/httphandler.ts:128-145](file://src/class/httphandler.ts#L128-L145)
|
|||
|
|
- [src/class/httphandler.ts:218-232](file://src/class/httphandler.ts#L218-L232)
|
|||
|
|
- [src/class/httphandler.ts:362-368](file://src/class/httphandler.ts#L362-L368)
|
|||
|
|
- [src/log.ts:15-24](file://src/log.ts#L15-L24)
|
|||
|
|
|
|||
|
|
## 结论
|
|||
|
|
本信令系统通过统一的数据模型与路由策略,在 HTTP 与 WebSocket 两种协议下实现了公共/私有两种通信模式的一致语义。Offer/Answer 与 ICE 候选者交换流程清晰,配合增量拉取与会话超时清理,满足实时性与稳定性需求。建议在生产环境中结合日志与监控接口进行持续观测与优化。
|
|||
|
|
|
|||
|
|
## 附录
|
|||
|
|
- 启动参数与脚本
|
|||
|
|
- 通过命令行参数或环境变量配置端口、HTTPS、协议类型、通信模式与日志级别。
|
|||
|
|
- 提供 npm scripts 用于开发与打包。
|
|||
|
|
|
|||
|
|
**章节来源**
|
|||
|
|
- [src/index.ts:20-42](file://src/index.ts#L20-L42)
|
|||
|
|
- [package.json:5-13](file://package.json#L5-L13)
|