Socket.IO实战搭建实时聊天室:从原生WebSocket到断线重连压测
第1章:OK so,先搞清楚 WebSocket 怎么用,别一上来就装库
兄弟们开机!这里是 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,聊天室、房间、重连一次安排
现在进入“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)这类服务,适合需要稳定查资料的人。觉得这期有用,收藏、评论区丢你的报错截图,我们下一期现场拆!