#### IdleStateHandler简介 IdleStateHandler的本质上也是一个channelhandler,也就是说可以把他加到pipeline里边。 IdleStateHandler的作用就是在某些情况下的触发一个IdleStateEvent。 某些情况: 在一段时间内 - 没有读 - 没有写 - 没有读写 在触发IdleStateEvent之后就可以被下游的的handler接收到。 比如10秒没有读操作,发出一个`READER_IDLE` ``` java ch.pipeline() .addLast(new IdleStateHandler(10, 0, 0, TimeUnit.SECONDS)) .addLast(new HeartTrigger()) } }); ``` 位于下游的`HeartTrigger`就可以收到这个事件 ``` java 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。 #### 相关代码 心跳包是自定义的数据结构,要考虑可能存在的半包/粘包问题 客户端发送心跳包 ``` java @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 ``` java @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); } } ```