🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
## 1. 心跳机制 ### 1.1 作用 > 1. Netty提供了对心跳机制的支持,以检测Netty的状态。具体实现方法是加入**IdleStateHandler**。 > 2. 在一定时间内处于长连接下,client与server没有数据交互时,应该进行心跳机制检查。 ~~~ /** * Creates a new instance firing {@link IdleStateEvent}s. * * @param readerIdleTimeSeconds * an {@link IdleStateEvent} whose state is {@link IdleState#READER_IDLE} * will be triggered when no read was performed for the specified * period of time. Specify {@code 0} to disable. * @param writerIdleTimeSeconds * an {@link IdleStateEvent} whose state is {@link IdleState#WRITER_IDLE} * will be triggered when no write was performed for the specified * period of time. Specify {@code 0} to disable. * @param allIdleTimeSeconds * an {@link IdleStateEvent} whose state is {@link IdleState#ALL_IDLE} * will be triggered when neither read nor write was performed for * the specified period of time. Specify {@code 0} to disable. */ public IdleStateHandler( int readerIdleTimeSeconds, int writerIdleTimeSeconds, int allIdleTimeSeconds) { this(readerIdleTimeSeconds, writerIdleTimeSeconds, allIdleTimeSeconds, TimeUnit.SECONDS); } ~~~ 实例化IdleStateHandler对象需要传递三个参数,上边的注释解释的很清楚: > 首先,这个实例是为了触发IdleStateEvent事件 > 1. readerIdleTimeSeconds: 当没有可读数据的时长达到这个时间时,触发事件 > 2. writerIdleTimeSeconds:当没有可写数据的时长达到这个时间时,触发事件 > 3. allIdleTimeSeconds:当没有可读数据和可写数据的时长达到这个时间时,触发事件,0表示取消这一触发条件 > 4. 默认时间单位是秒 如果超出以上条件规定的时间就会调用userEventTriggered()方法: ### 1.2 使用 1. 归根结底IdleStateHandler是Handler,所以一定要加入pipeline中,通常是在client端。 ~~~ bootstrap.handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { socketChannel.pipeline().addLast(new IdleStateHandler(20,10,0)); //加入心跳机制Handler socketChannel.pipeline().addLast(new ObjectEncoder()); socketChannel.pipeline().addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(null))); socketChannel.pipeline().addLast(new NettyClientHandler()); } }); ~~~ 2. 触发的作用函数 为了响应心跳机制事件,需要重写userEventTriggered()方法,对事件进行响应,这里对write进行了处理,想server发送数据,就是对read和write的时间进行记录,发现超过一定时间没有进行读写,就触发对应的事件。 ~~~ @Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { if (evt instanceof IdleStateEvent) { IdleStateEvent e = (IdleStateEvent) evt; switch (e.state()) { case WRITER_IDLE: PingMsg pingMsg=new PingMsg(); ctx.writeAndFlush(pingMsg); System.out.println("send ping to server----------"); break; default: break; } } ~~~ ### 1.2 Handler方法 #### 1.2.1 messageReceived() > 1. 和channelRead有一样的作用,用来接收网络数据 > 2. 需要编解码的才会去用messageReceived,一般都是使用ChannelRead来读取的。读一下SimpleChannelInboundHandler的源代码你就知道了,泛型不匹配,不会调用messageReceived的。 #### 1.2.2 channelRead 接收网络数据