netty心跳检测机制

既然是网络通信那么心跳检测肯定是离不开的,netty心跳检测分为读、写、全局

bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        // 注册一个心跳检测机制, 3秒未发生读事件进行触发,4秒为发生写事件进行触发,7秒未发生读写事件进行触发
        ch.pipeline().addLast(new IdleStateHandler(3, 4, 7, TimeUnit.SECONDS));
        // 发生心跳检测随即交个下一个handler.userEventTriggered(ctx, event)来处理
        ch.pipeline().addLast(new HBServerChannelHandler());
    }
});

/********************************IdleStateHandler********************************/

public IdleStateHandler(long readerIdleTime, long writerIdleTime, long allIdleTime, TimeUnit unit)


public void channelActive(ChannelHandlerContext ctx) throws Exception {
    // channel处于active状态随即进行初始化
    initialize(ctx);
    super.channelActive(ctx);
}


private void initialize(ChannelHandlerContext ctx) {
    switch (state) {
    case 1:
    case 2:
        return;
    }

    state = 1;
    initOutputChanged(ctx);
    // 根据设置的相关时间 创建不同的定时任务并提交到EventLoop
    lastReadTime = lastWriteTime = ticksInNanos();
    if (readerIdleTimeNanos > 0) {
        readerIdleTimeout = schedule(ctx, new ReaderIdleTimeoutTask(ctx),
                readerIdleTimeNanos, TimeUnit.NANOSECONDS);
    }
    if (writerIdleTimeNanos > 0) {
        writerIdleTimeout = schedule(ctx, new WriterIdleTimeoutTask(ctx),
                writerIdleTimeNanos, TimeUnit.NANOSECONDS);
    }
    if (allIdleTimeNanos > 0) {
        allIdleTimeout = schedule(ctx, new AllIdleTimeoutTask(ctx),
                allIdleTimeNanos, TimeUnit.NANOSECONDS);
    }
}

/********************************ReaderIdleTimeoutTask********************************/
private final class ReaderIdleTimeoutTask extends AbstractIdleTask {

    ReaderIdleTimeoutTask(ChannelHandlerContext ctx) {
        super(ctx);
    }

    @Override
    protected void run(ChannelHandlerContext ctx) {
        // 计算出下次心跳检测剩余的时间,因为定时任务可能被提前执行
        // 在之前分析EventLoop.run()的runAllTasks(),会把定时任务队列中未超过执行期限的定时任务添加到当前普通任务中来
        long nextDelay = readerIdleTimeNanos;
        if (!reading) {
            // ticksInNanos() - lastReadTime = 当前离上次读事件发生的间隔
            nextDelay -= ticksInNanos() - lastReadTime;
        }
        
        if (nextDelay <= 0) { // 小于0 表示已经超过设定的心跳检测时长
        
            // 心跳检测是不断重复检测,重新发起一个心跳检测任务
            readerIdleTimeout = schedule(ctx, this, readerIdleTimeNanos, TimeUnit.NANOSECONDS);

            boolean first = firstReaderIdleEvent;
            firstReaderIdleEvent = false;

            try {
                // 将当前心跳检测事件向后传递,随即交给下一个handler执行,handler.fireUserEventTriggered(context, event)
                IdleStateEvent event = newIdleStateEvent(IdleState.READER_IDLE, first);
                channelIdle(ctx, event);
            } catch (Throwable t) {
                ctx.fireExceptionCaught(t);
            }
        } else {
            // 还没有超出心跳检测的时间范围,则将剩余的时间当成下一次定时任务执行的时间
            readerIdleTimeout = schedule(ctx, this, nextDelay, TimeUnit.NANOSECONDS);
        }
    }
}

可以看出netty的心跳检测就是通过IdleStateHandler完成的,解释下IdleStateHandler构造方法的几个参数

  • readerIdleTime: 读事件的心跳检测时长

  • writerIdleTime:写事件的心跳检测时长

  • allIdleTime: 既包含读也包含写的心跳检测时长

发生心跳检测后,需要对对应的事件处理, 需要我们自己定义一个handler然后实现userEventTriggered(context, event)方法用来接收事件

posted @ 2020-12-28 22:39  努力工作的小码农  阅读(533)  评论(0编辑  收藏  举报