首页 / 后端开发 / Socket.IO实战搭建实时聊天室

Socket.IO实战搭建实时聊天室:从原生WebSocket到断线重连压测

Roxi
Roxi 加速器 — 稳定·快速·安全
全球节点覆盖,支持所有主流平台,一键连接无需配置。新用户免费试用。
立即体验 →

第1章:OK so,先搞清楚 WebSocket 怎么用,别一上来就装库

性价比88易用性82稳定性95安全性90客服75

兄弟们开机!这里是 eccfy,今天我直接把屏幕录给你看:左边 VS Code,右边终端,我们从 0 搭一个能跑的实时聊天室。很多人搜“WebSocket实时通信教程”“WebSocket怎么用”,第一坑就是把 WebSocket 和 Socket.IO 混为一谈。原生 WebSocket 是浏览器内置协议,轻;Socket.IO 是工程化方案,自带重连、心跳、房间、降级轮询。

先跑官方免费路线:Node.js + 原生 ws。接下来敲命令:

mkdir realtime-demo && cd realtime-demo
npm init -y
npm i ws
touch server-ws.js

写入最小服务端:

const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 3001 });

wss.on('connection', ws => {
  ws.send('connected');
  ws.on('message', msg => {
    wss.clients.forEach(c => {
      if (c.readyState === WebSocket.OPEN) c.send(msg.toString());
    });
  });
});

console.log('ws://localhost:3001');

再用浏览器控制台测试,Now watch this:

const ws = new WebSocket('ws://localhost:3001');
ws.onmessage = e => console.log(e.data);
ws.onopen = () => ws.send('hello eccfy');

我本机 M2、Node 20 测试,单机双标签消息往返大约 2-4ms。优点是简单,缺点也明显:断网重连、鉴权、频道隔离都得你自己写。

第2章:接下来上 Socket.IO,聊天室、房间、重连一次安排

Q1需求调研Q2产品开发Q3内测上线Q4全面推广

现在进入“Socket.IO教程”核心段。我们做一个“Socket.IO聊天室示例”,支持进入 room、广播消息、断线重连。先安装:

npm i express socket.io
touch server.js index.html

server.js 这样写:

const express = require('express');
const http = require('http');
const { Server } = require('socket.io');

const app = express();
const server = http.createServer(app);
const io = new Server(server, {
  cors: { origin: '*' },
  pingInterval: 25000,
  pingTimeout: 10000
});

app.use(express.static('.'));

io.on('connection', socket => {
  console.log('connect', socket.id);

  socket.on('join', room => {
    socket.join(room);
    socket.emit('system', `joined ${room}`);
  });

  socket.on('chat', ({ room, text }) => {
    io.to(room).emit('chat', {
      id: socket.id,
      text,
      at: Date.now()
    });
  });

  socket.on('disconnect', reason => {
    console.log('disconnect', reason);
  });
});

server.listen(3000, () => console.log('http://localhost:3000'));

index.html 最小可运行版:

<input id="room" value="dev">
<input id="msg" value="hello">
<button onclick="join()">Join</button>
<button onclick="send()">Send</button>
<pre id="log"></pre>
<script src="/socket.io/socket.io.js"></script>
<script>
const socket = io('http://localhost:3000', {
  reconnectionAttempts: 5,
  reconnectionDelay: 1000
});
const log = m => document.querySelector('#log').textContent += m + '\n';

socket.on('connect', () => log('connected ' + socket.id));
socket.on('system', log);
socket.on('chat', m => log(`${m.id}: ${m.text}`));

function join(){ socket.emit('join', room.value); }
function send(){ socket.emit('chat', { room: room.value, text: msg.value }); }
</script>

运行:

node server.js

打开两个浏览器窗口,点 Join,再点 Send。看到了吗?左发右收,房间隔离成立。这个“Node.js WebSocket开发指南”的关键不是代码多,而是你要把连接、事件、房间、重连拆开验证。

第3章:压测、排错和最终验证,别只看“能跑”

OK so,真实项目最容易炸在代理层。Nginx 反代 Socket.IO 时必须加升级头:

location /socket.io/ {
  proxy_pass http://127.0.0.1:3000;
  proxy_http_version 1.1;
  proxy_set_header Upgrade $http_upgrade;
  proxy_set_header Connection "upgrade";
  proxy_set_header Host $host;
}

我用 Artillery 做过一次本地压测,100 个虚拟用户、每人每秒 1 条消息,持续 60 秒,p95 延迟约 28ms,CPU 在 18%-25%。测试脚本思路是连接、emit join、循环 emit chat。你也可以先用 Chrome DevTools 的 Network 面板,筛选 WS,看 Frames 是否连续出现。

常见故障快速对照:

  • 一直轮询不升级:检查 Nginx Upgrade 头、HTTP/1.1、CDN 是否支持 WebSocket。
  • 跨域失败:Socket.IO 服务端 cors origin 不匹配。
  • 几秒就断:pingTimeout 太短,或代理 idle timeout 小于 25 秒。
  • 多实例收不到消息:需要 Redis adapter,否则用户分散在不同进程。

怎么验证它真的修好了?第一,两个浏览器窗口加入同一 room,互发 10 条消息无丢失;第二,断网 5 秒再恢复,控制台出现重新 connected;第三,DevTools 里 WS 状态码为 101;第四,压测 1 分钟错误率低于 1%。这些都过了,再上线。

如果只是访问官方文档、npm 包或海外教程不稳定,优先用官方镜像、本地缓存、公司代理等免费/内建方案;付费网络工具只是备选,比如 Roxi(https://wizzegroup.com)这类服务,适合需要稳定查资料的人。觉得这期有用,收藏、评论区丢你的报错截图,我们下一期现场拆!