如何实现Socket.io客户端可靠在线/离线统计及心跳服务端处理
实现Socket.io客户端可靠在线/离线统计方案
针对你现有客户端每5秒发送心跳的逻辑,服务端可以通过维护客户端心跳状态+定时超时检查的方式,实现10秒未收到心跳就标记离线的功能。下面是具体的实现步骤和代码示例:
1. 维护客户端心跳状态存储
首先需要在服务端创建一个存储结构,用来记录每个客户端的最后心跳时间(如果需要关联连接实例也可以一起存)。推荐使用Map,因为它的键值对操作更灵活:
// 存储客户端状态:key用socket.id(唯一标识),value包含pcName和最后心跳时间 const clientStatus = new Map();
2. 处理客户端心跳事件
在客户端连接时,监听heartbeat事件,收到心跳后立即更新对应客户端的最后心跳时间。另外建议让客户端连接后先完成注册,避免心跳时出现标识混乱:
io.on('connection', (socket) => { // 客户端连接后先发送pcName完成注册 socket.on('register', (pcName) => { socket.pcName = pcName; // 初始化心跳时间为当前时间 clientStatus.set(socket.id, { pcName: pcName, lastHeartbeat: Date.now() }); console.log(`${pcName}已上线`); }); // 监听客户端发送的heartbeat事件 socket.on('heartbeat', (pcName) => { // 校验pcName一致性,防止异常数据干扰 if (socket.pcName === pcName && clientStatus.has(socket.id)) { clientStatus.get(socket.id).lastHeartbeat = Date.now(); console.log(`收到${pcName}的心跳`); } }); // 处理客户端主动断开连接的情况 socket.on('disconnect', () => { if (clientStatus.has(socket.id)) { const { pcName } = clientStatus.get(socket.id); markOffline(pcName); clientStatus.delete(socket.id); } }); });
3. 定时检查心跳超时
设置一个定时任务,定期遍历所有客户端状态,判断是否超过10秒未收到心跳,触发离线标记函数:
// 每2秒执行一次检查(频率可根据业务调整,不用太频繁) setInterval(() => { const currentTime = Date.now(); // 遍历所有客户端状态 for (const [socketId, status] of clientStatus.entries()) { // 超过10秒未收到心跳,标记离线 if (currentTime - status.lastHeartbeat > 10000) { markOffline(status.pcName); clientStatus.delete(socketId); } } }, 2000);
4. 实现离线标记函数
根据你的业务需求,编写markOffline函数,比如更新数据库、通知其他客户端等:
function markOffline(pcName) { console.log(`${pcName}已离线`); // 这里添加你的业务逻辑: // 1. 更新数据库中该客户端的在线状态 // 2. 向其他客户端广播该客户端离线的消息 // 3. 记录离线日志等 }
额外注意事项
- 唯一性保证:用
socket.id作为状态存储的key比直接用pcName更可靠,避免多个客户端使用相同pcName导致状态混乱。 - Socket.io自带心跳:Socket.io本身有默认的ping/pong机制(默认25秒发ping,60秒未收到pong断开),但你的需求是10秒超时,所以自定义心跳更合适。
- 异常处理:可以在心跳事件中添加校验逻辑,比如验证
pcName的合法性,防止无效数据干扰状态统计。
内容的提问来源于stack exchange,提问作者Nik Hendricks
相关产品推荐
相关产品推荐

