Skip to main content

WebSocket 心跳机制

服务端主动发送 WebSocket 协议层 Ping 帧以保持连接存活。


概述

为防止中间代理、负载均衡器或防火墙在长时间无数据交互后断开连接,服务端在连接建立后立即启动心跳任务。

实现方式

采用 WebSocket 协议层 Ping 帧jakarta.websocket.RemoteEndpoint.Basic#sendPing),客户端 WebSocket 实现自动回复 Pong,无需应用层代码配合。

对比协议层 Ping应用层心跳消息
客户端改动无需需识别并回复
占用消息通道
触发 @OnMessage

参数

参数说明
Ping 间隔25 秒HEARTBEAT_INTERVAL_SECONDS
空闲超时60 秒MAX_IDLE_TIMEOUT_MS,略大于 2 倍 Ping 间隔

设计依据

  • 大多数代理/负载均衡器空闲超时为 60–120s,25s 间隔确保在超时前至少有 2 次心跳机会
  • 60s 空闲超时:若连续 2 次 Ping 无 Pong,判定连接已断
时间轴:
0s ─── 25s(Ping#1) ─── 50s(Ping#2) ─── 60s(idle timeout)
↓ 丢包 ↓ 响应 → 连接保持

生命周期

OnOpen 认证成功
├─ session.setMaxIdleTimeout(60000)
├─ startHeartbeat(session)
│ └─ scheduleAtFixedRate(每25s sendPing)

├─ ... 连接存活 ...

├─ OnClose / Ping 失败
│ └─ stopHeartbeat(session)
│ └─ cancel ScheduledFuture

└─ Spring 容器关闭
└─ @PreDestroy destroy()
└─ shutdown heartbeatExecutor

客户端无需额外处理

标准 WebSocket 客户端自动响应 Pong。连接断开时正常触发 onclose 事件,客户端重新连接即可。

const ws = new WebSocket("ws://ydzx.panretro.com/external/api/v1/im/imWebSocket/" + token);

ws.onclose = function(event) {
console.log("连接断开, code:", event.code);
// 可在此处实现重连逻辑
};

涉及文件

src/main/java/com/fareast/ntg/external/ws/ImWebSocketConnect.java

关键字段和方法:

  • heartbeatExecutor — 单线程调度器
  • heartbeatFutures — Session → ScheduledFuture 映射
  • startHeartbeat(Session) — 启动心跳
  • stopHeartbeat(Session) — 停止心跳
  • destroy() — 容器关闭时清理