对Netty的IdleStateHandler的认识

对Netty的IdleStateHandler的认识

首先,此Handler位于:io.netty.handler.timeout包下。

说明: 当一个channel在一定时间内没有发生:读、写操作时或读写都未发生时,就会触发一个IdleStateEvent事件。
事件的状态共有3种,对应的枚举类是:IdleState。

public enum IdleState {
    /**
     * No data was received for a while.
     */
    READER_IDLE,
    /**
     * No data was sent for a while.
     */
    WRITER_IDLE,
    /**
     * No data was either received or sent for a while.
     */
    ALL_IDLE
}

属性和说明

readerIdleTime :
如果在指定的时间周期内,没有读操作发生,就会触发一个状态为IdleState.READER_IDLE
的IdleStateEvent事件。如果要禁用它的话,就设置readerIdleTime=0。

writerIdleTime :
如果在指定的时间周期内,没有写操作发生的话,就会触发一个状态为IdleState.WRITER_IDLE
的IdleStateEvent事件。如果要禁用它的话,设置其writerIdleTime=0即可。

allIdleTime :
如果在指定的时间周期内,当既没有读也没有写操作发生的话,就触发一个状态为IdleState.ALL_IDLE事件。如果要禁用它的话,就设置allIdleTime=0。

举个例子

这里有个例子:当60秒内没有读操作的时候,也即发生READER_IDLE事件的时候,我们就关闭此连接。
并且如果30s没有写操作的话,也即发生WRITER_IDLE事件的时候,我们就发出一个ping消息。

代码即:

  public class MyChannelInitializer extends ChannelInitializer<Channel> {
     @Override
    public void initChannel(Channel channel) {
        channel.pipeline().addLast("idleStateHandler", new IdleStateHandler(60, 30, 0));
        channel.pipeline().addLast("myHandler", new MyHandler());
    }
}

需要提醒你的是,由IdleStateHandler触发的事件属于用户事件userEvent,即这样的事件是由用户自己触发的,
所以我们需要在自己的handler里面捕捉该事件并进行处理:


// Handler should handle the IdleStateEvent triggered by IdleStateHandler.


public class MyHandler extends ChannelDuplexHandler {
   @Override
  public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
      if (evt instanceof IdleStateEvent) {
          IdleStateEvent e = (IdleStateEvent) evt;
          if (e.state() == IdleState.READER_IDLE) {
              ctx.close();
          } else if (e.state() == IdleState.WRITER_IDLE) {
              ctx.writeAndFlush(new PingMessage());
          }
      }
  }
}

ServerBootstrap bootstrap = ...;
...
bootstrap.childHandler(new MyChannelInitializer());
...

实际使用

利用IdleStateHandler我们可以实现ping报文,从而检测连接的在线状态:
例如:
我们把readerIdleTime=30s,则如果在60s内没有入站流量的话即:当READER_IDLE事件发生时,此时可以认为对方的网络状态是有问题的,这时候,我们可以发送一个pingReq报文给它,如果它在一定时间内没有针对该pingReq报文做出响应即没有返回一个pingRes的话,我们可以认为对方已经掉线了,此时,我们就把此连接关闭。

另外,为了让对方感知到我们的存在,我们也会在空闲的时候,定时发送心跳给对端,此时可以把writerIdleTime=60 即:当WRITER_IDLE时,就给对端发送pingReq报文。

代码:

/**
     * 捕捉IdleStateEvent事件,并处理
     * @param ctx
     * @param evt
     * @throws Exception
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
      if(evt instanceof  IdleStateEvent){
          //如果发送读空闲的话,就发送一个ping消息,如果5秒内接收不到回复,就关闭连接
          IdleStateEvent  idleEvent=(IdleStateEvent)evt;
          if(idleEvent.state().equals(IdleState.READER_IDLE)){
              System.out.println("..........readerIdleTimeOut,will close the channel ...... ");
             ctx.close();
          }else if(idleEvent.state().equals(IdleState.WRITER_IDLE)) {
              //当写空闲时,就发送ping消息给对端
              //
              MqttFixedHeader fixedHeader = new MqttFixedHeader(MqttMessageType.PINGREQ, false, MqttQoS.AT_MOST_ONCE, false, 0);
              ctx.writeAndFlush(new MqttMessage(fixedHeader));
          }

      }else   ctx.fireUserEventTriggered(evt);//把事件往下传递

    }

推荐阅读更多精彩内容

  • 提醒:本篇适合有一定netty基础的读者阅读 心跳机制 何为心跳 所谓心跳, 即在 TCP 长连接中, 客户端和服...
    sprinkle_liz阅读 41,138评论 12 43
  •   JavaScript 与 HTML 之间的交互是通过事件实现的。   事件,就是文档或浏览器窗口中发生的一些特...
    霜天晓阅读 2,792评论 1 11
  • 什么是心跳机制? 心跳说的是在客户端和服务端在互相建立ESTABLISH状态的时候,如何通过发送一个最简单的包来保...
    tracy_668阅读 2,498评论 1 5
  • 本文是Netty文集中“Netty 那些事儿”系列的文章。主要结合在开发实战中,我们遇到的一些“奇奇怪怪”的问题,...
    tomas家的小拨浪鼓阅读 5,959评论 2 17
  • IT之家4月18日消息 去年有报道,美国耶鲁大学研究人员最新试验可能改变死亡的定义,他们成功让被砍下的猪脑在体外存...
    潮鞋木子阅读 113评论 0 1
  • paxos算法是为了解决分布式系统的一致性问题而生的。 分布式系统的一致性问题表现为在一个分布式系统中,所有的节点...
    飞过那沧海阅读 56评论 0 0
  • 我是日记星球212号星宝宝万儿,我在参加日记星球第七期21天蜕变之旅的复训,这是我在日记星球写的第109篇原创日记...
    万儿阅读 162评论 1 4
  • 今天在白天觉得过得非常的没有成就,因为没有做,出门拜访客户的事,只是在家里处理一些债券基金以及跟朋友上微信做多多的...
    c8e390dd84fe阅读 46评论 0 0