Files
2026-05-16 13:24:02 +08:00

377 lines
16 KiB
Markdown
Raw Permalink 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.
# 信令客户端
<cite>
**本文引用的文件**
- [client/src/signaling.js](file://client/src/signaling.js)
- [client/test/signaling.test.js](file://client/test/signaling.test.js)
- [client/test/mocksignaling.js](file://client/test/mocksignaling.js)
- [client/src/logger.js](file://client/src/logger.js)
- [src/signaling.ts](file://src/signaling.ts)
- [src/class/httphandler.ts](file://src/class/httphandler.ts)
- [src/websocket.ts](file://src/websocket.ts)
- [src/class/websockethandler.ts](file://src/class/websockethandler.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/server.ts](file://src/server.ts)
- [src/index.ts](file://src/index.ts)
- [package.json](file://package.json)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考量](#性能考量)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)
## 简介
本文件系统性地阐述信令客户端模块的实现机制与协议设计,覆盖以下主题:
- 与服务器的连接建立、消息收发与轮询拉取流程
- 信令协议的消息格式、事件类型与状态同步机制
- WebSocket 与 HTTP 轮询两种信令模式的实现差异与适用场景
- 客户端状态管理(连接状态监控、重连与错误处理)
- 实战示例(以“代码片段路径”形式给出,避免直接粘贴源码)
## 项目结构
前端信令客户端位于 client/src/signaling.js提供两类信令适配器
- HTTP 轮询适配器:基于 fetch 的 GET/PUT/POST/DELETE 接口,周期性拉取消息
- WebSocket 适配器:基于原生 WebSocket实时推送消息
后端信令服务位于 src/signaling.ts 与 src/class/httphandler.tsHTTP及 src/websocket.ts 与 src/class/websockethandler.tsWebSocket二者均通过统一的事件模型驱动前端。
```mermaid
graph TB
subgraph "前端"
FE_HTTP["HTTP 信令客户端<br/>client/src/signaling.js"]
FE_WS["WebSocket 信令客户端<br/>client/src/signaling.js"]
FE_LOGGER["日志工具<br/>client/src/logger.js"]
end
subgraph "后端"
BE_ROUTER["HTTP 路由<br/>src/signaling.ts"]
BE_HTTP_HANDLER["HTTP 处理器<br/>src/class/httphandler.ts"]
BE_WS_SERVER["WebSocket 服务器<br/>src/websocket.ts"]
BE_WS_HANDLER["WebSocket 处理器<br/>src/class/websockethandler.ts"]
end
FE_HTTP --> BE_ROUTER
FE_WS --> BE_WS_SERVER
BE_ROUTER --> BE_HTTP_HANDLER
BE_WS_SERVER --> BE_WS_HANDLER
FE_HTTP --- FE_LOGGER
FE_WS --- FE_LOGGER
```
**图表来源**
- [client/src/signaling.js:1-292](file://client/src/signaling.js#L1-L292)
- [src/signaling.ts:1-25](file://src/signaling.ts#L1-L25)
- [src/class/httphandler.ts:1-800](file://src/class/httphandler.ts#L1-L800)
- [src/websocket.ts:1-118](file://src/websocket.ts#L1-L118)
- [src/class/websockethandler.ts:1-479](file://src/class/websockethandler.ts#L1-L479)
**章节来源**
- [client/src/signaling.js:1-292](file://client/src/signaling.js#L1-L292)
- [src/signaling.ts:1-25](file://src/signaling.ts#L1-L25)
- [src/server.ts:1-90](file://src/server.ts#L1-L90)
- [src/index.ts:1-109](file://src/index.ts#L1-L109)
## 核心组件
- HTTP 信令客户端Signaling 类)
- 负责会话创建/删除、连接建立/断开、offer/answer/candidate/on-message 的发送与轮询接收
- 通过自定义事件分发消息connect/disconnect/offer/answer/candidate/on-message
- WebSocket 信令客户端WebSocketSignaling 类)
- 负责 WebSocket 连接生命周期、消息发送与事件分发
- 支持 participant-joined/participant-left/broadcast 等扩展事件
- 日志工具Logger
- 提供启用/禁用与多种级别输出,便于调试
**章节来源**
- [client/src/signaling.js:3-150](file://client/src/signaling.js#L3-L150)
- [client/src/signaling.js:152-292](file://client/src/signaling.js#L152-L292)
- [client/src/logger.js:1-30](file://client/src/logger.js#L1-L30)
## 架构总览
信令客户端与服务端通过两种模式协作:
- HTTP 轮询:客户端周期性 GET /signaling 拉取消息;服务端按会话聚合 offer/answer/candidate/connect/disconnect 并按时间戳排序返回
- WebSocket客户端直连 WebSocket服务端按连接组host/participants进行消息路由与广播
```mermaid
sequenceDiagram
participant C as "信令客户端"
participant S as "HTTP 服务端"
participant H as "HTTP 处理器"
C->>S : PUT /signaling (创建会话)
S->>H : createSession()
H-->>S : { sessionId }
S-->>C : { sessionId }
C->>S : PUT /signaling/connection (建立连接)
S->>H : createConnection()
H-->>S : { connectionId, polite }
S-->>C : { connect ... }
loop 轮询
C->>S : GET /signaling?fromtime=...
S->>H : getAll(fromtime)
H-->>S : { messages[], datetime }
S-->>C : { messages[], datetime }
C-->>C : 分发事件 (offer/answer/candidate/disconnect)
end
C->>S : DELETE /signaling (删除会话)
S->>H : deleteSession()
H-->>S : 200
S-->>C : 200
```
**图表来源**
- [client/src/signaling.js:30-97](file://client/src/signaling.js#L30-L97)
- [src/signaling.ts:15-18](file://src/signaling.ts#L15-L18)
- [src/class/httphandler.ts:615-641](file://src/class/httphandler.ts#L615-L641)
**章节来源**
- [client/src/signaling.js:30-149](file://client/src/signaling.js#L30-L149)
- [src/class/httphandler.ts:615-641](file://src/class/httphandler.ts#L615-L641)
## 详细组件分析
### HTTP 信令客户端Signaling 类)
- 会话管理
- start():若未获取 sessionId循环 PUT /signaling 创建会话,成功后进入轮询
- stop()DELETE /signaling 清理会话并重置 sessionId
- 连接管理
- createConnection()/deleteConnection()PUT/DELETE /signaling/connection
- 媒体协商
- sendOffer()/sendAnswer()/sendCandidate()POST /signaling/offer|answer|candidate
- 通用消息
- sendMessage()POST /signaling/on-message
- 消息拉取
- loopGetAll()GET /signaling?fromtime=lastTime解析 messages 数组并分发事件
- 事件分发
- disconnect/offer/answer/candidate/on-message 等事件通过 CustomEvent 派发
```mermaid
classDiagram
class Signaling {
+running boolean
+interval number
+sessionId string
+headers() object
+url(method, parameter) string
+start() void
+stop() void
+createConnection(connectionId) Promise
+deleteConnection(connectionId) Promise
+sendOffer(connectionId, sdp) Promise
+sendAnswer(connectionId, sdp) Promise
+sendCandidate(connectionId, candidate, sdpMid, sdpMLineIndex) Promise
+sendMessage(connectionId, message) Promise
+getAll(fromTime) Promise
-loopGetAll() void
}
```
**图表来源**
- [client/src/signaling.js:3-150](file://client/src/signaling.js#L3-L150)
**章节来源**
- [client/src/signaling.js:30-149](file://client/src/signaling.js#L30-L149)
### WebSocket 信令客户端WebSocketSignaling 类)
- 连接建立
- 构造函数根据协议选择 ws/wss监听 open/close/message
- start():等待 isWsOpen 为真
- stop():关闭连接并等待 isWsOpen 为假
- 消息发送
- createConnection()/deleteConnection()
- sendOffer()/sendAnswer()/sendCandidate()
- sendMessage():封装 type:"on-message" 数据
- 消息接收与事件分发
- onmessage解析 JSON按 type 分派 connect/disconnect/offer/answer/candidate/on-message/participant-joined/participant-left/broadcast
```mermaid
sequenceDiagram
participant C as "WebSocket 客户端"
participant WS as "WebSocket 服务端"
participant WH as "WebSocket 处理器"
C->>WS : CONNECT ws : //host
WS-->>C : onopen
C->>WS : {"type" : "connect","connectionId" : id}
WS->>WH : onConnect(ws, id)
WH-->>WS : 广播/通知
WS-->>C : {"type" : "connect", ...}
C->>WS : {"type" : "offer","from" : id,"data" : {"sdp",...}}
WS->>WH : onOffer(ws, data)
WH-->>WS : 路由/广播
WS-->>C : {"type" : "offer", ...}
C->>WS : {"type" : "on-message", "data" : {...}}
WS->>WH : onMessage(ws, data)
WH-->>WS : 转发
WS-->>C : {"type" : "on-message", ...}
C->>WS : CLOSE
WS-->>C : onclose
```
**图表来源**
- [client/src/signaling.js:152-292](file://client/src/signaling.js#L152-L292)
- [src/websocket.ts:27-115](file://src/websocket.ts#L27-L115)
- [src/class/websockethandler.ts:145-338](file://src/class/websockethandler.ts#L145-L338)
**章节来源**
- [client/src/signaling.js:152-292](file://client/src/signaling.js#L152-L292)
- [src/websocket.ts:27-115](file://src/websocket.ts#L27-L115)
- [src/class/websockethandler.ts:145-338](file://src/class/websockethandler.ts#L145-L338)
### 信令协议与消息格式
- HTTP 模式
- 会话PUT /signaling -> { sessionId }
- 连接PUT /signaling/connection -> { connectionId, polite }
- 消息GET /signaling?fromtime=... -> { messages[], datetime }
- 消息类型connect/disconnect/offer/answer/candidate/on-message
- offer/answer 字段connectionId, sdp, polite可选
- candidate 字段connectionId, candidate, sdpMLineIndex, sdpMid
- WebSocket 模式
- 连接:{"type":"connect","connectionId":id}
- 信令:{"type":"offer|answer|candidate","from":id,"data":{...},"participantId":...}
- 普通消息:{"type":"on-message","data":{...}}
- 扩展事件participant-joined/participant-left/broadcast
```mermaid
flowchart TD
A["HTTP 消息聚合"] --> B["按时间戳排序"]
B --> C["分发事件offer/answer/candidate/disconnect"]
D["WebSocket 消息路由"] --> E["按连接组(host/participants)转发"]
E --> F["广播/定向转发"]
```
**图表来源**
- [src/class/httphandler.ts:615-641](file://src/class/httphandler.ts#L615-L641)
- [src/class/websockethandler.ts:97-109](file://src/class/websockethandler.ts#L97-L109)
**章节来源**
- [src/class/httphandler.ts:398-641](file://src/class/httphandler.ts#L398-L641)
- [src/class/websockethandler.ts:214-338](file://src/class/websockethandler.ts#L214-L338)
### 状态管理与重连策略
- HTTP 轮询
- start() 中若 sessionId 为空则持续尝试创建会话,间隔由 interval 控制
- loopGetAll() 中每次拉取后更新 lastTimeRequest避免重复消费
- stop() 显式清理会话
- WebSocket
- 构造函数监听 open/closestart() 等待连接就绪
- 建议在 onclose 中实现指数退避重连(可在上层封装)
- 错误处理
- on-message 解析失败时记录错误日志
- HTTP 模式下 404/参数缺失等错误需上层捕获并提示
**章节来源**
- [client/src/signaling.js:30-97](file://client/src/signaling.js#L30-L97)
- [client/src/signaling.js:152-241](file://client/src/signaling.js#L152-L241)
- [client/src/logger.js:27-29](file://client/src/logger.js#L27-L29)
### 代码示例(以路径引用代替代码)
- 如何监听并处理 on-message 事件
- [client/src/signaling.js:74-83](file://client/src/signaling.js#L74-L83)
- 如何发送 offer/answer/candidate
- [client/src/signaling.js:117-138](file://client/src/signaling.js#L117-L138)
- [client/src/signaling.js:255-279](file://client/src/signaling.js#L255-L279)
- 如何启动/停止 HTTP 信令客户端
- [client/src/signaling.js:30-47](file://client/src/signaling.js#L30-L47)
- [client/src/signaling.js:93-97](file://client/src/signaling.js#L93-L97)
- 如何启动/停止 WebSocket 信令客户端
- [client/src/signaling.js:230-241](file://client/src/signaling.js#L230-L241)
- [client/src/signaling.js:236-241](file://client/src/signaling.js#L236-L241)
- 如何实现消息队列(建议思路)
- 使用内存队列暂存未处理的 on-message按顺序消费并回调处理函数
- 参考事件分发位置:[client/src/signaling.js:74-83](file://client/src/signaling.js#L74-L83)
- 如何调试信令通信
- 启用日志:[client/src/logger.js:3-9](file://client/src/logger.js#L3-L9)
- 观察网络请求与响应:[client/src/signaling.js:30-149](file://client/src/signaling.js#L30-L149)
**章节来源**
- [client/src/signaling.js:30-149](file://client/src/signaling.js#L30-L149)
- [client/src/logger.js:3-9](file://client/src/logger.js#L3-L9)
## 依赖关系分析
- 前端依赖
- client/src/signaling.js 依赖 client/src/logger.js
- 测试依赖 client/test/signaling.test.js 与 client/test/mocksignaling.js
- 后端依赖
- src/server.ts 注册 /signaling 路由并挂载 HTTP 与 WebSocket 信令
- src/signaling.ts 定义路由与鉴权中间件(会话校验)
- HTTP 侧src/class/httphandler.ts 负责会话/连接/消息持久化与聚合
- WebSocket 侧src/websocket.ts 与 src/class/websockethandler.ts 负责连接组与消息路由
```mermaid
graph LR
P["package.json"] --> FE["client/src/signaling.js"]
P --> BE_S["src/server.ts"]
BE_S --> BE_R["src/signaling.ts"]
BE_R --> BE_H["src/class/httphandler.ts"]
BE_S --> BE_W["src/websocket.ts"]
BE_W --> BE_WH["src/class/websockethandler.ts"]
FE --> LOG["client/src/logger.js"]
```
**图表来源**
- [package.json:1-60](file://package.json#L1-L60)
- [src/server.ts:14-29](file://src/server.ts#L14-L29)
- [src/signaling.ts:1-25](file://src/signaling.ts#L1-L25)
- [src/class/httphandler.ts:1-120](file://src/class/httphandler.ts#L1-L120)
- [src/websocket.ts:1-21](file://src/websocket.ts#L1-L21)
- [src/class/websockethandler.ts:1-66](file://src/class/websockethandler.ts#L1-L66)
**章节来源**
- [package.json:1-60](file://package.json#L1-L60)
- [src/server.ts:14-29](file://src/server.ts#L14-L29)
- [src/signaling.ts:1-25](file://src/signaling.ts#L1-L25)
## 性能考量
- HTTP 轮询
- 通过 fromtime 参数避免重复拉取,提升效率
- 合理设置 interval避免过于频繁导致带宽与 CPU 压力
- WebSocket
- 服务端支持心跳检测(注释中可见),可结合客户端 ping/pong 保持长连稳定
- 连接组广播需控制消息规模,避免风暴
- 会话超时
- HTTP 处理器定期清理长时间无请求的会话,降低资源占用
**章节来源**
- [src/class/httphandler.ts:218-232](file://src/class/httphandler.ts#L218-L232)
- [src/class/websockethandler.ts:404-430](file://src/class/websockethandler.ts#L404-L430)
## 故障排查指南
- 无法获取 sessionId
- 确认 start() 已调用且网络可达
- 查看控制台日志与网络面板
- 参考:[client/src/signaling.js:30-47](file://client/src/signaling.js#L30-L47)
- on-message 解析失败
- 客户端会记录错误日志,检查消息格式与编码
- 参考:[client/src/signaling.js:74-83](file://client/src/signaling.js#L74-L83)
- WebSocket 连接异常
- 检查协议ws/wss、主机与端口配置
- 关注 onclose 回调,必要时实现重连
- 参考:[client/src/signaling.js:169-176](file://client/src/signaling.js#L169-L176)
- 私有模式下未收到对端 offer/answer
- 确认双方已建立相同 connectionId 的连接
- 参考测试用例对私有模式行为的断言
- 参考:[client/test/signaling.test.js:214-434](file://client/test/signaling.test.js#L214-L434)
**章节来源**
- [client/src/signaling.js:30-97](file://client/src/signaling.js#L30-L97)
- [client/src/signaling.js:152-241](file://client/src/signaling.js#L152-L241)
- [client/test/signaling.test.js:214-434](file://client/test/signaling.test.js#L214-L434)
## 结论
本信令客户端模块提供了统一的事件接口,兼容 HTTP 轮询与 WebSocket 两种模式。HTTP 模式适合受限网络环境WebSocket 模式具备更低延迟与更丰富的连接组能力。通过清晰的事件分发与日志工具,开发者可以快速集成并调试信令流程。
## 附录
- 数据模型Offer/Answer/Candidate
- Offersdp、datetime、polite
- Answersdp、datetime
- Candidatecandidate、sdpMLineIndex、sdpMid、datetime
- 参考:
- [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)