心跳检测应用场景:在集群内节点与节点之间互相感知彼此是否存活。
- 为什么需要心跳检测?netty不是提供断开连接的回调方法么?
在app的应用场景中,手机如果开飞行模式或者强制关机,服务端是感知不到tcp长连接已经关闭的,这时候就需要服务端向客户端发送心跳包来检测连接是否已经断开。
netty除了提供了各种编解码器,还提供了各种处理器handler,比如空闲状态IdleStateHandler
服务端实现
/** * Created by fubin on 2019/7/13. */ public class BeartBeatServer { public static void main(String[] args) { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try{ ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.group(bossGroup,workerGroup) .channel(NioServerSocketChannel.class) //增加日志handler .handler(new LoggingHandler(LogLevel.INFO)) .childHandler(new HeartBeatInitializer()); ChannelFuture channelFuture = serverBootstrap.bind(8899).sync(); channelFuture.channel().closeFuture().sync(); } catch (InterruptedException e) { e.printStackTrace(); } finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } } class HeartBeatInitializer extends ChannelInitializer<SocketChannel> { protected void initChannel(SocketChannel socketChannel) throws Exception { ChannelPipeline channelPipeline = socketChannel.pipeline(); //netty还提供了各种各样的处理器,比如空闲检测的handler channelPipeline.addLast(new IdleStateHandler(5,7,10, TimeUnit.SECONDS)); channelPipeline.addLast(new HeartBeatHandler()); } } class HeartBeatHandler extends ChannelInboundHandlerAdapter { @Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { IdleStateEvent event = (IdleStateEvent)evt; String eventType = null; switch (event.state()){ case READER_IDLE: eventType = "读空闲"; break; case WRITER_IDLE: eventType = "写空闲"; break; case ALL_IDLE: eventType = "读写空闲"; break; } System.out.println(ctx.channel().remoteAddress() + "超时事件:" + eventType); ctx.channel().close(); } }
客户端实现
client代码可以使用 上一篇netty socket服务的聊天程序的client
Netty心跳检测核心Handler IdleStateHandler
的API解释
当一个Channel没有执行读,写或者两者都没执行时,会触发一个IdleStateEvent事件。
支持的空闲idle
状态
属性 | 含义 |
---|---|
readerIdleTime | 一个IdleStateEvent的状态为IdleState.READER_IDLE事件将在指定期间不执行读取操作时触发,指定0禁用 |
writerIdleTime | 一个IdleStateEvent的状态为IdleState.WRITE_IDLE事件将在指定期间不执行写操作时触发,指定0禁用 |
allIdleTime | 一个IdleStateEvent的状态为IdleState.ALL_IDLE事件将在指定期间读写操作都不执行时触发,指定0禁用 |
//在30秒没有出栈流量时发送ping消息的示例 //当60秒没有入栈流量时连接关闭 class MyChannelInitializer extends ChannelInitializer<Channel>{ @Override protected void initChannel(Channel ch) { ch.pipeline().addLast("idleStateHandler",new IdleStateHandler(60,30,0)); ch.pipeline().addLast("myHandler",null); } } 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("写空闲!"); } } } } //server main ServerBootstrap bootstrap = ...; bootstrap.childHandler(new MyChannelInitializer());