WebSocket多客户端场景下断连检测失效问题如何修复?
问题原因与修复方案
你的代码核心问题是所有客户端共享了全局的定时器变量tm,导致多个客户端连接时定时器互相覆盖,功能异常。具体错误点如下:
- 全局变量
tm存储定时器引用:第二个客户端连接执行ping()时,会直接覆盖第一个客户端绑定的定时器ID,导致第一个客户端的超时逻辑丢失,超时后只会触发最新客户端的断连判定 - 定时器清除API用错:
pong()里使用clearInterval()清除setTimeout()创建的定时器,API不匹配,根本无法正常清除超时计时 - 消息处理分支逻辑错误:非
__ping__的消息分支中,既没有赋值msg变量,也没有执行日志输出语句,还直接把未定义的msg发送给客户端,会触发运行时报错
修复后的完整代码
const WebSocket = require("ws"); const express = require("express"); const app = express(); const server = require("http").createServer(app); const url = require('url'); const PORT = process.env.PORT || 3000; const wss = new WebSocket.Server({ server: server }); app.get("/", (req, res) => res.send("Test.")); // 给每个连接的客户端单独绑定定时器,不再使用全局变量 function ping(ws, clientId) { // 把定时器挂载到当前ws实例上,每个客户端独立存储 ws.tm = setTimeout(function () { console.log(`[-] ${clientId} Disconnected`); wss.emit("customClose", clientId); // 触发断连后主动关闭对应客户端的连接 ws.terminate(); }, 5000); } function pong(ws, clientId) { // 用clearTimeout清除定时器 clearTimeout(ws.tm); ping(ws, clientId); } wss.on("connection", function connection(ws, req) { var queryData = url.parse(req.url,true).query; const clientId = queryData.id; // 给当前连接的客户端初始化专属定时器 ping(ws, clientId); console.log(`[+] ${req.socket.remoteAddress} Connected`); wss.clients.forEach(function each(client) { if (client.readyState === WebSocket.OPEN) { const message = { type: "alert", msg: `${clientId} has Connected.`, }; client.send(JSON.stringify(message), { binary: false }); } }); ws.on("message", function incoming(message) { if (message == "__ping__") { console.log(`[!] Ping Received from ${req.socket.remoteAddress}`); pong(ws, clientId); } else { console.log(`[!] Message Received from ${req.socket.remoteAddress}: ${message}`); wss.clients.forEach(function each(client) { if (client.readyState === WebSocket.OPEN) { const msg = JSON.stringify({ type: "message", content: message.toString() }); client.send(msg, { binary: false }); } }); } }); // 新增客户端主动断连的处理逻辑,清除定时器 ws.on("close", () => { clearTimeout(ws.tm); console.log(`[*] Client ${clientId} actively disconnected`); }); }); wss.addListener("customClose", function (m) { wss.clients.forEach(function each(client) { if (client.readyState === WebSocket.OPEN) { const message = { type: "alert", msg: `${m} has Disconnected.`, }; client.send(JSON.stringify(message), { binary: false }); } }); }); server.listen(PORT, () => console.log(`Listening on port ${PORT}`));
修复说明
- 移除了全局
tm变量,改为将每个客户端的定时器挂载到对应ws连接实例上,实现连接级别的隔离,多个客户端的定时器不会互相干扰 - 把
clearInterval替换为clearTimeout,匹配定时器创建的API - 修复了非ping消息分支的逻辑错误,补全了日志输出、消息封装逻辑,避免未定义变量报错
- 新增了客户端主动断连的
close事件监听,及时清理残留定时器,避免内存泄漏 - 修正了代码中拼写错误的Receieved为Received,测试页内容Temst为Test
内容的提问来源于stack exchange,提问作者Ballistic Swami
相关产品推荐
相关产品推荐

