Netty的心跳机制

  • Post author:
  • Post category:其他




一、引入

在 TCP 保持长连接的过程中,可能会出现断网等网络异常出现,异常发生的时候, client 与 server 之间如果没有交互的话,它们是无法发现对方已经掉线。



二、工作原理

在 client 与 server 之间在一定时间内没有数据交互时, 即处于 idle 状态时, 客户端或服务器就会发送一个特殊的数据包给对方, 当接收方收到这个数据报文后, 也立即发送一个特殊的数据报文, 回应发送方, 此即一个 PING-PONG 交互。所以, 当某一端收到心跳消息后, 就知道了对方仍然在线, 这就确保 TCP 连接的有效性。

TCP 实际上自带的就有长连接选项,本身是也有心跳包机制,也就是 TCP 的选项:SO_KEEPALIVE。但是,TCP 协议层面的长连接灵活性不够。所以,一般情况下我们都是在应用层协议上实现自定义心跳机制的,也就是在 Netty 层面通过编码实现。通过 Netty 实现心跳机制的话,核心类是 IdleStateHandler 。



三、实现



Netty

中, 实现心跳机制的关键是

IdleStateHandler

public IdleStateHandler(int readerIdleTimeSeconds, int writerIdleTimeSeconds, int allIdleTimeSeconds) {
    this((long)readerIdleTimeSeconds, (long)writerIdleTimeSeconds, (long)allIdleTimeSeconds, TimeUnit.SECONDS);
}


参数的含义:


  • readerIdleTimeSeconds

    : 读超时. 即当在指定的时间间隔内没有从

    Channel

    读取到数据时, 会触发一个

    READER_IDLE



    IdleStateEvent

    事件.

  • writerIdleTimeSeconds

    : 写超时. 即当在指定的时间间隔内没有数据写入到

    Channel

    时, 会触发一个

    WRITER_IDLE



    IdleStateEvent

    事件.

  • allIdleTimeSeconds

    : 读/写超时. 即当在指定的时间间隔内没有读或写操作时, 会触发一个

    ALL_IDLE



    IdleStateEvent

    事件.

**注意:**这三个参数默认的时间单位是秒。

心跳处理类:

ClientIdleStateTrigger

/**
 * <p>
 *  用于捕获{@link IdleState#WRITER_IDLE}事件(未在指定时间内向服务器发送数据),然后向<code>Server</code>端发送一个心跳包。
 * </p>
 */
public class ClientIdleStateTrigger extends ChannelInboundHandlerAdapter {

    public static final String HEART_BEAT = "heart beat!";

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleState state = ((IdleStateEvent) evt).state();
            if (state == IdleState.WRITER_IDLE) {
                // write heartbeat to server
                ctx.writeAndFlush(HEART_BEAT);
            }
        } else {
            super.userEventTriggered(ctx, evt);
        }
    }

}



四、源码剖析

在这里插入图片描述

第254行代码其实表示该方法只是进行了透传,不做任何业务逻辑处理,让channelPipe中的下一个

handler

处理

channelRead

方法,但是记录了一下这里的调用时间


channelActive方法

在这里插入图片描述


initialize方法

在这里插入图片描述

这边会触发一个Task,ReaderIdleTimeoutTask,这个task是部分源码

在这里插入图片描述

341行是这样的,用当前时间减去最后一次

channelRead

方法调用的时间,假如这个结果是6s,说明最后一次调用

channelRead

已经是6s之前的事情了,你设置的是5s,那么nextDelay则为-1,说明超时了,那么354行则会触发

userEventTriggered

方法,如果没有超时则不触发userEventTriggered方法。

在这里插入图片描述



五、总结


IdleStateHandler

这个类会根据你设置的超时参数的类型和值,循环去检测

channelRead



write

方法多久没有被调用了,如果这个时间超过了你设置的值,那么就会触发对应的事件,read触发read,write触发write,all触发all

  • 如果超时了,则会调用

    userEventTriggered

    方法,且会告诉你超时的类型
  • 如果没有超时,则会循环定时检测,除非你将

    IdleStateHandler

    移除

    Pipeline

在这里插入图片描述


JVM内存泄漏和内存溢出的原因



JVM常用监控工具解释以及使用



Redis 常见面试题(一)



ClickHouse之MaterializeMySQL引擎(十)



三种实现分布式锁的实现与区别



线程池的理解以及使用


号外!号外!


最近面试BAT,整理一份面试资料,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。想获取吗?如果你想提升自己,并且想和优秀的人一起进步,感兴趣的朋友,可以在扫码关注下方公众号。资料在公众号里静静的躺着呢。。。


  • 喜欢就收藏

  • 认同就点赞

  • 支持就关注

  • 疑问就评论


一键四连,你的offer也四连

————————————————————————————————————————————————————————————————

本文作者:Java技术债务

原文链接:

https://www.cuizb.top/myblog/article/1645434283


版权声明: 本博客所有文章除特别声明外,均采用 CC BY 3.0 CN协议进行许可。转载请署名作者且注明文章出处。



版权声明:本文为qq_40124555原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。