概述
在学习 Netty 的 IdlerStateHander 类的过程中,看到它实现的心跳功能在我们项目中正好需要用到,于是心里跃跃欲试。于是模仿书籍、网上的一些例子来自己来实现一个简单的心跳功能 ,感受一下。很快就写完了,和其他的案例如出一辙,于是激动的启动服务端,待服务端启动完毕后,立马又启动客户端。接着就是静悄悄地等待:读超时(我设定的是 5 秒)--->触发任务---->读超时---> 触发任务..。可是这样的理想情况一直没有出现...
为什么了?
整个过程比较艰难,大致经历了如下:添加 debug 日志 ---> 打断点查看 Netty 的 IdlerStateHandler 源码 ---> 一度以为 Netty 源码有问题 --->发现了一个 debug 日志 ([id: 0xb528342d, /127.0.0.1:57320 :> /127.0.0.1:8655] INACTIVE)。
是的,当出现 INACTIVE 的时候意味着该通道已经关闭了,通道都已经关闭了,自然和该通道相关 IdlerStateHandler 对应的资源也释放了,所以心跳也就停止了。
那为啥 Channel 会关闭了?
我看了客户端所有代码,确认了客户端没有关闭 Channel 的操作,自然原因就定位到服务端了(因为 Channel 是用于服务端和客户端通信的,所以无论哪一方进行了关闭操作,该 Channel 都会关闭的)。果不其然,我在服务端发现了这样一段代码
@Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { //由于 “.addListener(ChannelFutureListener.CLOSE)” 的存在,当读完信息之后,就会关闭该通道 ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE); System.out.println("read complete"); }
所以我果断移除掉了“.addListener(ChannelFutureListener.CLOSE)”,之后心跳功能恢复了.....
总结
对于 IdleStateHandler 类的心跳功能,一定要确保 Channel 是保持连接状态的