You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Node.js的ws模块中跟踪WebSocket客户端连接与断开并维护数组

解决ws模块中WebSocket客户端连接跟踪不稳定问题

需求:在Node.js中使用ws模块实现WebSocket服务器的客户端连接跟踪,动态将客户端实例加入/移出数组,支持通过索引向特定客户端发送消息。

现有代码能正常添加客户端,但断开时偶尔无法移除,出现“幽灵WebSocket”问题,原代码如下:

clients = [];

function addClient(ws, wss, WebSocket) {
    clients.push(ws);
    console.log("Client Connect: " + clients.indexOf(ws) + ". " + clients.length + " Online")

    ws.on('message', function incoming(data, isBinary) {
        wss.clients.forEach(function each(client) {
            if(client != ws && client.readyState == WebSocket.OPEN) {
                const msg = isBinary ? data : data.toString();
                client.send(msg);
            }
        })
    })
    ws.onclose = function() {
        removeClient(ws);
    }
}

function removeClient(ws) {
    let indx = clients.indexOf(ws)
    clients = clients.splice(clients.indexOf(ws), 1)
    console.log("Client Disconnect: " + indx + ". " + clients.length + " Online")
}


module.exports = {
    clients, addClient, removeClient
}

问题分析

  1. splice用法错误:Array.splice()会直接修改原数组,并返回被删除的元素组成的数组。原代码中clients = clients.splice(...)会把clients变量替换成被删除的单个元素数组,而非剩下的客户端列表,导致后续索引查找完全混乱。
  2. close事件绑定不可靠:直接赋值ws.onclose会覆盖之前可能存在的close事件监听,改用ws.on('close', callback)的方式更安全,避免事件丢失。
  3. 索引有效性判断缺失:当indexOf(ws)返回-1时(比如重复触发close事件),执行splice会导致无意义操作甚至错误,需要先判断索引是否有效。

修正后的代码

// 用let声明变量,避免全局污染
let clients = [];

function addClient(ws, wss, WebSocket) {
    clients.push(ws);
    const clientIndex = clients.indexOf(ws);
    console.log(`Client Connect: ${clientIndex}. ${clients.length} Online`);

    ws.on('message', function incoming(data, isBinary) {
        wss.clients.forEach(function each(client) {
            if(client !== ws && client.readyState === WebSocket.OPEN) {
                const msg = isBinary ? data : data.toString();
                client.send(msg);
            }
        });
    });

    // 改用on('close')绑定事件,避免覆盖原有监听
    ws.on('close', () => {
        removeClient(ws);
    });

    // 可选:监听error事件,避免未处理错误导致进程崩溃
    ws.on('error', (err) => {
        console.error('Client error:', err);
        removeClient(ws);
    });
}

function removeClient(ws) {
    const index = clients.indexOf(ws);
    // 先判断索引是否有效,避免无效操作
    if (index !== -1) {
        // 直接修改原数组,不需要重新赋值
        clients.splice(index, 1);
        console.log(`Client Disconnect: ${index}. ${clients.length} Online`);
    }
}

module.exports = {
    clients, addClient, removeClient
};

额外优化建议

  • 如果需要频繁通过索引操作客户端,建议用**Map对象映射**替代数组,比如const clients = new Map(),用客户端的唯一标识(如ws._socket.remoteAddress或自定义ID)作为key,WebSocket实例作为value,查找和删除效率更高,也能避免数组索引混乱的问题。
  • 发送消息前务必检查客户端的readyState,确保连接处于WebSocket.OPEN状态,避免发送失败抛出错误。

内容的提问来源于stack exchange,提问作者Vinny

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 22:47:50