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);
            }
        }
    }
}
全部评论

相关推荐

点赞 收藏 评论
分享
牛客网
牛客企业服务