Netty应用之心跳检测
心跳检测
服务侧可使用Netty中提供IdleStateHandler
类来检测客户端的心跳,服务端只需在IdleStateHandler
之后的ChannelInboundHandler
重写心跳超时所触发的userEventTriggered
事件方法即可。
添加IdleStateHandler和ServerHeartbeatHandler
ch.pipeline().addLast(new IdleStateHandler(3, 0 ,0)); ch.pipeline().addLast(new ServerHeartbeatHandler());
心跳检测方法
public class ServerHeartbeatHandler extends ChannelInboundHandlerAdapter { private int readerIdleCount = 0; @Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { IdleStateEvent stateEvent = (IdleStateEvent) evt; if (IdleState.READER_IDLE.equals(stateEvent.state())) { readerIdleCount++; System.out.println("超时一次"); } if (3 < readerIdleCount) { // 通知客户端关闭连接 ctx.channel().writeAndFlush("close"); ctx.channel().close(); System.out.println("释放客户端连接"); } } }
心跳检测源码
IdleStateHandler继承自ChannelInboundHandlerAdapter类,也属于ChannelInboundHandler,所以在客户端连接服务端的时候,会执行channelActive
方法
@Override public void channelActive(ChannelHandlerContext ctx) throws Exception { initialize(ctx); super.channelActive(ctx); } private void initialize(ChannelHandlerContext ctx) { //... if (readerIdleTimeNanos > 0) { // 生成周期任务 readerIdleTimeout = schedule(ctx, new ReaderIdleTimeoutTask(ctx), readerIdleTimeNanos, TimeUnit.NANOSECONDS); } //... } private final class ReaderIdleTimeoutTask extends AbstractIdleTask { @Override protected void run(ChannelHandlerContext ctx) { long nextDelay = readerIdleTimeNanos; if (!reading) { nextDelay -= ticksInNanos() - lastReadTime; } // 周期内未收到客户端请求 if (nextDelay <= 0) { // 重新生成周期任务 readerIdleTimeout = schedule(ctx, this, readerIdleTimeNanos, TimeUnit.NANOSECONDS); boolean first = firstReaderIdleEvent; firstReaderIdleEvent = false; try { // 读空闲事件 IdleStateEvent event = newIdleStateEvent(IdleState.READER_IDLE, first); // 触发下一个ChannelInboundHandler的userEventTriggered方法 channelIdle(ctx, event); } catch (Throwable t) { ctx.fireExceptionCaught(t); } } } }