搭建第一个 WebSocket 服务器:使用 ws 库创建 WebSocket 服务器、监听连接与消息事件

好,咱们开始动手了。

信令服务器说白了就是一个中间人,帮两个浏览器互相递话。WebSocket 是目前最常用的递话方式。我最早做 WebRTC 项目时,第一件事就是搭这个 WebSocket 服务器。那时候踩了不少坑,今天我把最稳的路径告诉你。

为什么选 ws 库?

Node.js 生态里 WebSocket 库不少,比如 socket.iowsuWebSockets.js。我个人习惯用 ws,原因很简单:

  • 轻量——没有多余的回退机制,就是纯 WebSocket
  • 稳定——npm 周下载量几千万,社区验证过
  • API 简洁——你花 10 分钟就能上手

socket.io 虽然自带房间和自动重连,但它的协议不是标准 WebSocket。如果你后面要对接其他客户端(比如 iOS、Android),ws 更干净。

我的建议:信令服务器用 ws 就够了。socket.io 那些高级功能,信令场景下基本用不到。

初始化项目

先建一个文件夹,然后初始化 npm 项目:

mkdir webrtc-signaling-server
cd webrtc-signaling-server
npm init -y

接着安装 ws:

npm install ws

嗯,就这一步。没有其他依赖。

创建 WebSocket 服务器

新建一个 server.js,写下面这段代码:

const WebSocket = require('ws');

const wss = new WebSocket.Server({ port: 8080 });

console.log('WebSocket 服务器已启动,监听端口 8080');

就这么几行,一个 WebSocket 服务器就跑起来了。你运行 node server.js,控制台会打印出启动信息。

注意:端口 8080 可能被占用。我建议你开发时用 8080,上线前改成 443 并用 Nginx 做反向代理。我曾经在演示现场发现端口被占用,场面一度很尴尬。

监听连接事件

服务器建好了,但还没处理任何连接。我们需要监听 connection 事件:

wss.on('connection', function connection(ws, req) {
  console.log('新客户端连接,IP:', req.socket.remoteAddress);
});

这里的 ws 是当前连接的实例,req 是 HTTP 请求对象。你可以通过 req 拿到客户端的 IP、URL 参数等信息。

为什么会需要 IP?我在做信令服务器时,经常用它做简单的访问控制——比如只允许内网 IP 连接。

监听消息事件

连接建立后,客户端会发消息过来。我们监听 message 事件:

ws.on('message', function incoming(message) {
  console.log('收到消息:', message.toString());
});

注意 message 默认是 Buffer 类型,需要转成字符串。如果你确定客户端只发文本,也可以直接 message.toString()

实际项目中,消息通常是 JSON 格式。我会这样处理:

ws.on('message', function incoming(data) {
  try {
    const parsed = JSON.parse(data);
    console.log('收到 JSON 消息:', parsed);
  } catch (e) {
    console.error('消息格式错误:', data.toString());
  }
});

嗯,这里要注意:信令消息必须是结构化的。如果客户端发来乱码,直接抛异常会断开连接。我习惯用 try-catch 包一层,至少让服务器不崩溃。

完整代码示例

把上面几段拼起来,就是一个可用的信令服务器雏形:

const WebSocket = require('ws');

const wss = new WebSocket.Server({ port: 8080 });

wss.on('connection', function connection(ws, req) {
  console.log('新客户端连接,IP:', req.socket.remoteAddress);

  ws.on('message', function incoming(data) {
    try {
      const message = JSON.parse(data);
      console.log('收到消息:', message);

      // 这里后面会加信令处理逻辑
      // 比如转发 offer、answer、ICE 候选

    } catch (e) {
      console.error('消息解析失败:', data.toString());
    }
  });

  ws.on('close', function close() {
    console.log('客户端断开连接');
  });

  ws.on('error', function error(err) {
    console.error('连接错误:', err);
  });
});

console.log('WebSocket 信令服务器已启动,端口 8080');

你想想看,这个服务器现在能做什么?

  • 接受 WebSocket 连接
  • 接收 JSON 消息
  • 打印日志
  • 处理断开和错误

说白了,骨架已经搭好了。后面我们只需要往 message 处理里填信令逻辑就行。

测试服务器

你可以用浏览器控制台测试:

const ws = new WebSocket('ws://localhost:8080');
ws.onopen = () => {
  ws.send(JSON.stringify({ type: 'ping' }));
};
ws.onmessage = (e) => {
  console.log('收到:', e.data);
};

打开浏览器 F12,粘贴这段代码。如果控制台没有报错,说明连接成功。

小技巧:我开发时习惯开两个浏览器标签页,一个模拟呼叫方,一个模拟应答方。这样不用写客户端代码就能验证信令流程。

核心逻辑流程图

下面这张图展示了 WebSocket 信令服务器的核心工作流程:

WebSocket 信令服务器核心流程 客户端 A 呼叫方 信令服务器 ws://localhost:8080 客户端 B 应答方 连接 连接 发送 JSON 消息 解析 JSON + 路由 接收转发消息 服务器监听的事件 connection - 新客户端连接 message - 收到客户端消息 close / error - 断开或异常

常见问题与避坑

问题 原因 解决方法
连接被拒绝 端口被占用或防火墙拦截 换端口或检查防火墙规则
消息收不到 客户端发送的是二进制数据 服务端用 message.toString() 转换
连接频繁断开 心跳机制缺失 后面章节会讲如何实现心跳
JSON 解析报错 客户端发送了非 JSON 格式 用 try-catch 包裹解析逻辑
我曾经踩过的坑:有一次生产环境上,客户端连接后 30 秒就断开。查了半天发现是 Nginx 的 proxy_read_timeout 默认只有 60 秒,而 WebSocket 长连接需要更长的超时时间。记得调整反向代理的超时配置。

小结

今天我们做了三件事:

  • 用 ws 库创建了一个 WebSocket 服务器
  • 监听了 connection 事件,拿到每个客户端连接
  • 监听了 message 事件,处理 JSON 格式的信令消息

这个服务器虽然简单,但已经是信令服务器的核心骨架。后面所有的信令逻辑——房间管理、消息转发、ICE 候选交换——都是在这个基础上加功能。

你可以在本地跑起来试试。打开两个浏览器标签页,都连上这个服务器,然后互相发消息。能通,就说明你迈出了第一步。

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