基于TCP Socket 实现心跳机制
在 Node.js 中使用 TCP Socket 实现心跳机制(Heartbeat)的核心目的是检测连接是否存活,避免因网络波动或客户端异常断开导致的"僵尸连接"。以下是详细实现步骤及代码示例:
1. **基本原理
- 心跳机制:服务端定期向客户端发送探测消息(如
ping
),客户端需响应pong
。 - 超时检测:若在指定时间内未收到响应,判定连接失效并主动关闭。
- 重置计时器:每次正常通信(收到数据或心跳响应)时,重置超时检测。
2. 服务端实现(使用 net
模块)
const net = require('net');
// 创建 TCP 服务器
const server = net.createServer((socket) => {
console.log('Client connected:', socket.remoteAddress);
// 初始化心跳配置
const HEARTBEAT_INTERVAL = 3000; // 3秒发送一次心跳
const HEARTBEAT_TIMEOUT = 10000; // 10秒未响应则断开
let heartbeatTimer = null;
let timeoutTimer = null;
// 发送心跳包
const sendHeartbeat = () => {
if (socket.writable) {
socket.write('ping'); // 发送心跳标识
console.log('Sent ping to client');
}
};
// 启动心跳定时器
const startHeartbeat = () => {
heartbeatTimer = setInterval(sendHeartbeat, HEARTBEAT_INTERVAL);
resetTimeout();
};
// 重置超时检测
const resetTimeout = () => {
if (timeoutTimer) clearTimeout(timeoutTimer);
timeoutTimer = setTimeout(() => {
console.log('Client timeout, closing connection');
socket.destroy(); // 强制关闭连接
}, HEARTBEAT_TIMEOUT);
};
// 监听客户端数据
socket.on('data', (data) => {
const message = data.toString();
if (message === 'pong') {
console.log('Received pong from client');
resetTimeout(); // 收到响应,重置超时检测
} else {
console.log('Received data:', message);
// 处理业务逻辑...
}
});
// 启动心跳机制
startHeartbeat();
// 监听连接关闭
socket.on('close', () => {
console.log('Client disconnected');
clearInterval(heartbeatTimer);
clearTimeout(timeoutTimer);
});
// 错误处理
socket.on('error', (err) => {
console.error('Socket error:', err.message);
});
});
server.listen(3000, () => {
console.log('Server listening on port 3000');
});
3. 客户端实现(Node.js 客户端示例)
const net = require('net');
// 连接到服务端
const client = net.createConnection({ port: 3000 }, () => {
console.log('Connected to server');
});
// 监听服务端数据
client.on('data', (data) => {
const message = data.toString();
if (message === 'ping') {
console.log('Received ping from server');
client.write('pong'); // 响应心跳
} else {
console.log('Received data:', message);
// 处理业务逻辑...
}
});
// 监听连接关闭
client.on('close', () => {
console.log('Connection closed');
});
// 错误处理
client.on('error', (err) => {
console.error('Connection error:', err.message);
});
4. 关键逻辑说明
-
心跳发送
- 服务端每隔
HEARTBEAT_INTERVAL
(如 3 秒)发送ping
。 - 客户端需响应
pong
,否则服务端会触发超时关闭。
- 服务端每隔
-
超时检测
- 每次发送心跳或收到正常数据时,重置超时计时器。
- 若
HEARTBEAT_TIMEOUT
(如 10 秒)内未收到响应,判定连接失效。
-
资源清理
- 连接关闭时,清除所有定时器(
clearInterval
和clearTimeout
)。
- 连接关闭时,清除所有定时器(
5. 优化建议
- 协议设计:使用固定格式(如
HEARTBEAT|pong
)区分心跳与业务数据。 - 重连机制:客户端检测到连接关闭后,可自动重连。
- 动态配置:根据网络状况动态调整心跳间隔和超时时间。
- TCP Keep-Alive:可结合系统级 Keep-Alive(需手动启用):
socket.setKeepAlive(true, 60000); // 1分钟无活动发送探测包
6. 测试验证
- 启动服务端和客户端。
- 观察控制台日志,确认心跳正常(
ping
和pong
交替出现)。 - 手动断开客户端网络,服务端应在 10 秒后检测到超时并关闭连接。
总结
通过应用层心跳机制,可以有效检测 TCP 连接的存活性,避免因意外断开导致的资源泄漏。实际项目中可根据需求调整心跳间隔和超时阈值,并结合业务逻辑完善错误处理。