1. 心跳检测机制设计
- 心跳消息格式:
- 设计一个简单的心跳消息,例如一个包含特定标识符(如
{"type":"heartbeat","timestamp":1678945678}
)的JSON对象。这个标识符可用于服务端识别该消息为心跳消息,时间戳可用于计算心跳间隔。
- 心跳发送频率:
- 根据不同网络环境进行调整。对于高延迟网络,适当降低发送频率,避免过多的无效传输,例如设置为每30秒发送一次心跳;对于NAT网络,由于可能存在端口映射超时等问题,心跳频率可相对高一些,如每15秒发送一次。
- 客户端可以使用
setInterval
函数来定时发送心跳消息,例如:
const interval = 15 * 1000; // 15秒
const heartbeatInterval = setInterval(() => {
const heartbeatMessage = { type: 'heartbeat', timestamp: new Date().getTime() };
socket.send(JSON.stringify(heartbeatMessage));
}, interval);
2. 处理网络中断
- 客户端检测:
- 当客户端发送心跳消息后,若在一定时间(如2倍心跳间隔)内未收到服务端的心跳响应,可认为发生网络中断。
- 可以通过记录上次收到心跳响应的时间,结合当前时间来判断,例如:
let lastHeartbeatResponseTime = new Date().getTime();
const heartBeatTimeout = 2 * interval;
const checkHeartbeat = () => {
const currentTime = new Date().getTime();
if (currentTime - lastHeartbeatResponseTime > heartBeatTimeout) {
console.log('Network interruption detected');
// 处理网络中断逻辑,如尝试重连
}
};
setInterval(checkHeartbeat, 5 * 1000); // 每5秒检查一次
- 服务端检测:
- 服务端同样记录每个客户端最后一次发送心跳的时间,若超过一定时间(如3倍心跳间隔)未收到心跳,可关闭该连接并释放资源。
const clients = {};
const heartbeatTimeoutServer = 3 * interval;
io.on('connection', (socket) => {
clients[socket.id] = { lastHeartbeat: new Date().getTime() };
socket.on('heartbeat', (data) => {
clients[socket.id].lastHeartbeat = new Date().getTime();
});
setInterval(() => {
for (const clientId in clients) {
const currentTime = new Date().getTime();
if (currentTime - clients[clientId].lastHeartbeat > heartbeatTimeoutServer) {
console.log(`Client ${clientId} seems to be offline, closing connection`);
io.to(clientId).disconnectSockets();
delete clients[clientId];
}
}
}, 10 * 1000); // 每10秒检查一次
});
3. 重连机制
- 指数退避算法:
- 客户端在检测到网络中断后,使用指数退避算法来尝试重连。每次重连失败后,等待时间翻倍,例如:
let reconnectInterval = 1000; // 初始重连间隔1秒
const maxReconnectInterval = 60 * 1000; // 最大重连间隔60秒
const attemptReconnect = () => {
const socket = io.connect(serverUrl);
socket.on('connect', () => {
console.log('Reconnected successfully');
reconnectInterval = 1000; // 重连成功,重置间隔
});
socket.on('connect_error', () => {
console.log('Reconnection failed');
reconnectInterval = Math.min(reconnectInterval * 2, maxReconnectInterval);
setTimeout(attemptReconnect, reconnectInterval);
});
};
4. 安全性考虑
- 消息加密:
- 对心跳消息进行加密传输,可使用TLS/SSL协议对整个连接进行加密,Node.js中使用
https
模块或者 socket.io
等库的安全配置选项来实现。
- 身份验证:
- 在心跳消息中附带简单的身份验证信息,如客户端在连接时获取的JWT(JSON Web Token),服务端验证JWT的有效性,确保心跳消息来自合法客户端。
5. 资源消耗问题
- 心跳频率优化:
- 如前面提到,根据不同网络环境合理设置心跳频率,避免过于频繁的心跳导致过多的网络和系统资源消耗。
- 服务端资源管理:
- 服务端定期清理长时间未发送心跳的客户端连接,释放内存等资源,避免资源泄漏。同时,在处理心跳消息时,尽量减少复杂的计算和数据库查询操作,以降低CPU消耗。