websocket后端实现心跳检测,并定时清理异常的连接

张开发
2026/4/15 9:58:56 15 分钟阅读

分享文章

websocket后端实现心跳检测,并定时清理异常的连接
要实现WebSocket心跳检测和异常连接清理核心思想是记录每个连接的最后活动时间 (Last Seen Timestamp)并设置一个定时任务 (Timer/Scheduler)来定期检查这些时间戳是否超出了预设的容忍范围Timeout。1. 核心原理与策略A. 心跳机制 (Heartbeat Mechanism)心跳可以有两种实现方式客户端主动 Ping/Pong (推荐):服务器每隔NNN秒向所有连接发送一个PING消息。客户端必须在TTT秒内回复一个PONG。如果服务器在TTT秒后没有收到PONG则认为该连接超时或中断触发清理。服务端状态跟踪 (Timeout):服务器不依赖客户端的明确心跳而是基于实际消息的接收时间来判断连接是否“活跃”。当服务器接收到任何数据时立即更新该连接的last_activity标记。如果在设定的最大空闲时间TidleT_{idle}Tidle​内没有收到任何活动则视为异常。B. 清理逻辑 (Cleanup Logic)主要采用服务端状态跟踪 (Timeout)的策略来实现定时清理。数据结构: 需要一个映射表来存储所有活跃的连接及其状态。Connections{Connection ID:{Socket Object,Last Activity Timestamp}}\text{Connections} \{ \text{Connection ID} : \{ \text{Socket Object}, \text{Last Activity Timestamp} \} \}Connections{Connection ID:{Socket Object,Last Activity Timestamp}}定时任务 (The Cleaner): 启动一个后台线程或使用框架提供的定时调度器每隔Δt\Delta tΔt秒执行一次检查。在每次检查中遍历Connections\text{Connections}Connections中的所有条目。对于每个连接计算CurrentTime−Last Activity Timestamp\text{CurrentTime} - \text{Last Activity Timestamp}CurrentTime−Last Activity Timestamp。如果结果≥Tidle\ge T_{idle}≥Tidle​空闲时间超过阈值则执行清理操作a. 关闭对应的 Socket 连接。b. 从Connections\text{Connections}Connections映射中移除该连接记录。2. 示例架构 (以 Node.js/WebSocket 为例)假设我们使用 Node.js 的ws库作为后端实现。步骤一连接管理类设计我们需要一个类来集中管理所有连接的状态和清理逻辑。classConnectionManager{constructor(idleTimeoutMs300000){// 默认空闲超时时间5分钟// 存储所有连接状态: { socket: wsInstance, lastActivity: timestamp }this.connectionsnewMap();this.IDLE_TIMEOUTidleTimeoutMs;}addConnection(socket){constconnectionIdDate.now()Math.random().toString(36).substring(2,9);this.connections.set(connectionId,{socket:socket,lastActivity:Date.now()});console.log(Connection added with ID:${connectionId});}updateActivity(connectionId){if(this.connections.has(connectionId)){this.connections.get(connectionId).lastActivityDate.now();}}removeConnection(connectionId){constdatathis.connections.get(connectionId);if(datadata.socket){console.log([Cleanup] Closing connection ID:${connectionId});// 关键步骤关闭Socketdata.socket.end();}this.connections.delete(connectionId);}/** * 定时清理函数 (Heartbeat Cleaner) */cleanupConnections(){constnowDate.now();console.log(\n--- Running Heartbeat Check at${newDate().toISOString()}---);for(const[id,data]ofthis.connections.entries()){constidleTimenow-data.lastActivity;if(idleTimethis.IDLE_TIMEOUT){console.warn([Cleanup Triggered] Connection ID${id}timed out. Idle for:${(idleTime/1000).toFixed(1)}s);this.removeConnection(id);}}console.log(Total active connections:${this.connections.size});}}module.exportsConnectionManager;步骤二集成到 WebSocket 服务器在主服务器中每次消息接收后调用updateActivity。同时你需要启动一个定时器来周期性地调用cleanupConnections。constWebSocketrequire(ws);constConnectionManagerrequire(./ConnectionManager);// 1. 初始化管理器 (设置超时时间为1分钟)constmanagernewConnectionManager(60000);// 60秒空闲超时// 2. 创建WebSocket ServerconstwssnewWebSocket.Server({port:8080});wss.on(connection,functionconnection(ws){console.log(Client connected.);// 当新连接建立时添加到管理器manager.addConnection(ws);// --- 监听来自客户端的消息 (更新活动时间) ---ws.on(message,functionincoming(message){// 接收到任何消息立即更新该连接的最后活动时间constconnectionIdObject.keys(manager.connections).find(keymanager.connections.get(key).socketws);if(connectionId){manager.updateActivity(connectionId);}});ws.on(close,(){// 客户端主动关闭连接时立即清理记录constconnectionIdObject.keys(manager.connections).find(keymanager.connections.get(key).socketws);if(connectionId){manager.removeConnection(connectionId);}});});// 3. 启动定时清理任务 (例如每10秒检查一次)constCLEANUP_INTERVAL10000;// 10秒setInterval((){manager.cleanupConnections();},CLEANUP_INTERVAL);console.log(WebSocket Server started and Heartbeat monitoring enabled.);3. 总结与注意事项环节目的实现方式注意事项状态记录跟踪连接的“新鲜度”使用Map或对象存储lastActivity时间戳。确保 ID 的唯一性和高效的查找。活动更新标记连接是活跃的任何消息on(message)到达时立即更新该记录的时间戳。这是防止误判超时的关键。定时清理发现和移除死连接使用setInterval或异步调度器定期遍历所有记录。定时间隔 (Δt\Delta tΔt) 需要平衡检测频率和资源消耗。异常处理连接关闭在cleanupConnections中使用socket.end()来强制关闭流。确保在尝试操作已关闭的资源时不会抛出错误。通过这种结合了实时活动跟踪和后台定时检查的机制WebSocket后端就能有效地检测到那些长时间没有交互的“僵尸”连接并及时将其清理掉从而释放服务器资源保证系统的健康运行。

更多文章