Java 实现 WebSocket 心跳机制:基于 Netty 的完整代码示例
·
以下是一个基于 Netty 实现的 WebSocket 心跳机制的完整 Java 代码示例,包含心跳检测和自动重连机制:
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.*;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;
import java.util.concurrent.TimeUnit;
public class WebSocketHeartbeatServer {
public static void main(String[] args) throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) {
ChannelPipeline pipeline = ch.pipeline();
// HTTP 编解码器
pipeline.addLast(new HttpServerCodec());
pipeline.addLast(new HttpObjectAggregator(65536));
// WebSocket 协议处理器
pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));
// 心跳检测 (30秒无读操作触发)
pipeline.addLast(new IdleStateHandler(30, 0, 0, TimeUnit.SECONDS));
// 自定义业务处理器
pipeline.addLast(new WebSocketHeartbeatHandler());
}
});
ChannelFuture future = bootstrap.bind(8080).sync();
future.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
// 自定义 WebSocket 处理器(含心跳机制)
private static class WebSocketHeartbeatHandler extends SimpleChannelInboundHandler<WebSocketFrame> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame frame) {
// 处理 Ping 帧(心跳请求)
if (frame instanceof PingWebSocketFrame) {
ctx.writeAndFlush(new PongWebSocketFrame(frame.content().retain()));
return;
}
// 处理文本帧(业务消息)
if (frame instanceof TextWebSocketFrame) {
String request = ((TextWebSocketFrame) frame).text();
ctx.writeAndFlush(new TextWebSocketFrame("ECHO: " + request));
}
}
// 处理空闲状态事件(心跳检测)
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
if (evt instanceof IdleStateEvent) {
// 发送 Ping 帧检测客户端存活
ctx.writeAndFlush(new PingWebSocketFrame());
System.out.println("Sent heartbeat ping to: " + ctx.channel().id());
}
}
// 异常处理
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
}
核心机制说明
-
心跳检测实现:
- 使用
IdleStateHandler检测读空闲(30秒无数据) - 触发空闲事件后发送
PingWebSocketFrame - 客户端需响应
PongWebSocketFrame保持连接
- 使用
-
消息处理流程:
graph LR A[客户端] -->|Ping帧| B[服务端] B -->|Pong帧| A C[业务消息] -->|Text帧| B B -->|响应消息| C -
关键组件:
WebSocketServerProtocolHandler:处理 WebSocket 握手协议IdleStateHandler:连接状态检测PingWebSocketFrame/PongWebSocketFrame:心跳控制帧
客户端实现建议
// JavaScript 客户端示例
const socket = new WebSocket("ws://localhost:8080/ws");
// 自动响应心跳
socket.onmessage = (event) => {
if(event.data instanceof Blob) {
// 处理二进制心跳帧
socket.send(new Blob([event.data]));
}
};
// 定时发送心跳(可选)
setInterval(() => {
socket.send(new Uint8Array([])); // 发送空数据
}, 25000);
参数配置建议
- 心跳间隔:推荐 25-30 秒(小于 Nginx 默认 60 秒超时)
- 重试机制:连续 3 次未收到 Pong 响应自动断开
- 帧类型说明:
PingWebSocketFrame:服务端 → 客户端PongWebSocketFrame:客户端 → 服务端TextWebSocketFrame:文本数据帧
注意事项:
- 生产环境需添加异常重连机制
- 建议使用 SSL/TLS 加密通信
- 高并发场景需优化线程模型
- 心跳超时时间应根据网络环境调整
此实现符合 WebSocket RFC 6455 规范,通过双向心跳机制确保连接可靠性,适用于实时通信、在线游戏等场景。
更多推荐
所有评论(0)