DengQN·一个普通程序员;
使用IdleStateHandler实现心跳机制
2019-05-04 01:02 50
#操作#心跳#读#没有#写#客户端#服务端#监听#包

IdleStateHandler简介

IdleStateHandler的本质上也是一个channelhandler,也就是说可以把他加到pipeline里边。

IdleStateHandler的作用就是在某些情况下的触发一个IdleStateEvent。

某些情况:

在一段时间内

  • 没有读
  • 没有写
  • 没有读写

在触发IdleStateEvent之后就可以被下游的的handler接收到。

比如10秒没有读操作,发出一个READER_IDLE

ch.pipeline()
    .addLast(new IdleStateHandler(10, 0, 0, TimeUnit.SECONDS))
    .addLast(new HeartTrigger())
    }
});

位于下游的HeartTrigger就可以收到这个事件

public class HeartTrigger extends ChannelInboundHandlerAdapter {
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            // do something
        } else {
            super.userEventTriggered(ctx, evt);
        }
    }
}

心跳

心跳的模型很简单,客户端和服务端创建连接后,使用IdleStateHandler监听操作, 如果在一定的时间内没有*操作,主动发送一个心跳包造成写操作。

客户端的操作对应着服务端的操作。也就是说客户端的心跳包或造成服务端的读操作。

而服务端监听channel的读操作,如过超时没有读操作,将关闭channel(连接)。

而服务端的读监听时间间隔要比客户端的写监听时间间隔稍长一点,不然会因为略微的延迟而关闭channel。

相关代码

心跳包是自定义的数据结构,要考虑可能存在的半包/粘包问题

客户端发送心跳包

@Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            if (((IdleStateEvent) evt).state() == IdleState.WRITER_IDLE) {
                logger.info("发个心跳包告诉服务器自己没死。。");
                ctx.writeAndFlush(new TransData.Builder()
                        .type(TransData.TYPE_HT)
                        .build());
            }
        }
    }

服务端长时间没收到客户都的东西就关了channel

@Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            if (((IdleStateEvent) evt).state() == IdleState.READER_IDLE) {
                logger.info("过久没收到客户端心跳,断开连接");
                ctx.close();
            }
        } else {
            super.userEventTriggered(ctx, evt);
        }
    }