用 set 维护 websocket 在线用户连接列表高效可靠:利用其自动去重和 o(1) 增删特性,需在 connection/close/error 时同步增删,并广播前校验 readystate;进阶场景应结合 map 实现用户维度管理。

用 Set 维护 WebSocket 在线用户连接列表是常见且高效的做法,关键在于:每个连接(WebSocket 实例)作为唯一值存入 Set,利用其自动去重和 O(1) 增删特性;同时需在连接建立、关闭、异常时同步更新 Set,并确保广播逻辑遍历的是当前有效的连接。
用 Set 存储活跃的 WebSocket 连接对象
Set 天然适合存储唯一连接,因为每个 WebSocket 实例引用不同,即使同一客户端重连也会生成新实例,不会误判为重复。
示例初始化:
const onlineUsers = new Set();
连接建立时添加,关闭/异常时及时删除
必须在生命周期关键节点同步更新 Set,否则会残留断连但未清理的连接,导致广播失败或报错(如调用已关闭连接的 send())。
- 收到新连接(如
wss.on('connection', ws => {...}))时,执行onlineUsers.add(ws) - 监听
ws.on('close', () => onlineUsers.delete(ws)) - 监听
ws.on('error', () => onlineUsers.delete(ws))(防止因网络错误未触发 close)
广播消息时安全遍历 Set 中的有效连接
不能假设 Set 中所有连接都可写。需在发送前检查 ws.readyState === WebSocket.OPEN,跳过关闭或正在关闭的状态。
推荐广播写法:
function broadcast(message) {
for (const ws of onlineUsers) {
if (ws.readyState === WebSocket.OPEN) {
ws.send(message);
} else {
onlineUsers.delete(ws); // 清理无效连接
}
}
}
进阶建议:绑定用户身份时避免仅依赖连接对象
如果业务需要按“用户 ID”广播(如私聊、房间),不要只靠 Set 存连接——应额外用 Map 建立 userId → ws 映射,并配合心跳检测维持映射准确性。
例如:
const userConnections = new Map(); // userId → Set<websocket> // 登录后:userConnections.get(userId)?.add(ws) || userConnections.set(userId, new Set([ws])) // 下线时:userConnections.get(userId)?.delete(ws)</websocket>
此时 Set 仍用于单连接管理,而 Map + Set 组合支撑更复杂的在线状态逻辑。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











