25、信令服务器测试:使用 WebSocket 客户端模拟信令交互,验证信令服务器逻辑。

信令服务器,说白了就是 WebRTC 的“调度中心”。

它不负责传音视频数据,但负责帮两个 Peer 牵线搭桥。如果信令服务器挂了,或者逻辑有 bug,那你的 WebRTC 应用根本跑不起来。我见过不少团队,花大把时间调音视频质量,结果发现是信令层在丢消息——这种坑,踩一次就记住了。

所以,今天咱们聊聊怎么用 WebSocket 客户端模拟信令交互,把信令服务器的逻辑测透。

为什么需要模拟信令交互?

你想想看,信令服务器本质上就是个消息中转站。它接收客户端的 SDP、ICE Candidate,然后转发给对端。逻辑本身不复杂,但容易出问题的点在于:

  • 消息格式对不对? 比如 JSON 字段名拼错了,或者类型不对。
  • 房间管理有没有 bug? 两个人能不能正确加入同一个房间?第三个人进来会怎样?
  • 异常情况怎么处理? 比如客户端中途断连,或者发了个非法消息。

这些问题,靠浏览器跑完整 WebRTC 流程来测,效率太低了。你每次都要打开两个页面,点按钮,看日志…… 我个人习惯是,先用 WebSocket 客户端模拟信令交互,把核心逻辑跑通,再上浏览器集成测试。

测试环境准备

我们需要一个 WebSocket 客户端工具。我推荐用 wscat(Node.js 命令行工具)或者 WebSocket King(浏览器插件)。

安装 wscat 很简单:

npm install -g wscat

然后连接你的信令服务器:

wscat -c ws://localhost:8080

连接成功后,你就可以手动发送 JSON 消息了。

核心测试场景

我一般会按以下顺序测试,从简单到复杂:

1. 连接与心跳

先确认 WebSocket 能连上,并且服务器会回复心跳。比如:

// 客户端发送
{"type": "ping"}

// 期望服务器回复
{"type": "pong"}

嗯,这一步看似简单,但能快速发现网络问题或服务器没启动。

2. 创建房间与加入房间

模拟两个客户端,一个创建房间,一个加入房间。

客户端 A:

{"type": "create-room", "roomId": "test123"}

期望回复:

{"type": "room-created", "roomId": "test123"}

客户端 B:

{"type": "join-room", "roomId": "test123"}

期望回复:

{"type": "room-joined", "roomId": "test123"}

同时,客户端 A 应该收到一条通知:

{"type": "peer-joined", "peerId": "clientB"}

我曾经遇到过一个问题:服务器在创建房间时,忘记把创建者加入房间成员列表。结果客户端 A 永远收不到 peer-joined 消息。这种 bug 用模拟测试一测就现形。

3. SDP 与 ICE 转发

这是信令的核心功能。模拟客户端 A 发送 SDP offer:

{
  "type": "sdp",
  "to": "clientB",
  "sdp": "v=0\no=- 123456 2 IN IP4 127.0.0.1\ns=-\nt=0 0\n..."
}

期望客户端 B 收到:

{
  "type": "sdp",
  "from": "clientA",
  "sdp": "v=0\no=- 123456 2 IN IP4 127.0.0.1\ns=-\nt=0 0\n..."
}

ICE Candidate 同理:

{
  "type": "ice-candidate",
  "to": "clientB",
  "candidate": "candidate:1 1 UDP 2122252543 192.168.1.1 54321 typ host"
}

这里要注意:消息中的 to 字段必须正确。我见过一个 bug,服务器把 to 和 from 搞反了,结果 A 发的 offer 又回到了 A 自己手里……

4. 异常场景测试

光测正常流程不够,还得测异常。我习惯用以下用例:

  • 加入不存在的房间: 应该返回错误消息,而不是崩溃。
  • 重复加入同一房间: 服务器应该拒绝,或者给出明确提示。
  • 发送非法 JSON: 服务器应该优雅地断开连接,而不是挂掉。
  • 客户端断连: 服务器应该通知房间内其他成员。

举个例子,测试加入不存在的房间:

// 客户端发送
{"type": "join-room", "roomId": "nonexistent"}

// 期望回复
{"type": "error", "message": "Room not found"}

如果服务器直接返回 200 OK 或者没反应,那就有问题了。

自动化测试脚本

手动测几次还行,但每次改完代码都要重测,那就太累了。我建议写个简单的自动化脚本,用 Node.js 的 ws 库来模拟多个客户端。

下面是一个示例脚本,模拟两个客户端完成一次完整的信令交互:

const WebSocket = require('ws');

function createClient(name) {
  const ws = new WebSocket('ws://localhost:8080');
  ws.on('open', () => {
    console.log(`${name} connected`);
  });
  ws.on('message', (data) => {
    console.log(`${name} received:`, data.toString());
  });
  return ws;
}

// 模拟客户端 A 和 B
const clientA = createClient('ClientA');
const clientB = createClient('ClientB');

// 等待连接建立
setTimeout(() => {
  // A 创建房间
  clientA.send(JSON.stringify({type: 'create-room', roomId: 'auto-test'}));
}, 1000);

setTimeout(() => {
  // B 加入房间
  clientB.send(JSON.stringify({type: 'join-room', roomId: 'auto-test'}));
}, 2000);

setTimeout(() => {
  // A 发送 SDP offer
  clientA.send(JSON.stringify({
    type: 'sdp',
    to: 'ClientB',
    sdp: 'fake-sdp-offer'
  }));
}, 3000);

setTimeout(() => {
  // B 发送 SDP answer
  clientB.send(JSON.stringify({
    type: 'sdp',
    to: 'ClientA',
    sdp: 'fake-sdp-answer'
  }));
}, 4000);

这个脚本跑起来,你就能看到完整的消息流转。如果哪一步没收到预期回复,那就是 bug。

信令测试的核心逻辑图

下面这张图,展示了一次典型的信令交互流程。我把它画出来,方便你对照测试:

信令服务器测试:模拟交互流程 客户端 A 信令服务器 客户端 B create-room room-created join-room room-joined peer-joined SDP offer SDP offer SDP answer SDP answer ICE candidates ICE candidates

测试结果验证

测试完了,怎么判断信令服务器逻辑对不对?我列个检查清单:

测试项 预期结果 常见失败原因
连接与心跳 收到 pong 回复 服务器未启动、端口错误
创建房间 返回 room-created 房间 ID 重复、数据库写入失败
加入房间 双方收到通知 房间不存在、成员列表未更新
SDP 转发 对端收到完整 SDP 消息格式错误、to 字段错误
ICE 转发 对端收到 candidate candidate 字段缺失、序列化错误
异常消息 返回 error 或断开 服务器未做校验、异常未捕获

核心原则:信令服务器的测试,重点不是性能,而是消息的完整性和正确性。每条消息都必须被正确转发,不能丢,不能错,不能乱序。

我的小技巧:在信令服务器里加一个“消息日志”功能,把每个 WebSocket 连接收发的消息都打印出来。测试时对照日志,一眼就能看出问题出在哪一步。

注意:不要在生产环境直接测试!用本地或测试环境的信令服务器。我曾经手滑在线上环境发了个非法消息,导致服务器重启…… 嗯,从那以后我学乖了。

好了,用 WebSocket 客户端模拟信令交互,说白了就是手动扮演两个 Peer,看服务器能不能正确传话。这个方法简单、高效,能帮你把信令层的 bug 扼杀在摇篮里。等你把这一套跑熟了,再去集成 WebRTC 的完整流程,会顺畅很多。


公众号:蓝海资料掘金营,微信deep3321