Netty 应用:心跳检测

心跳检测应用场景:在集群内节点与节点之间互相感知彼此是否存活。

  • 为什么需要心跳检测?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());

 

posted @ 2019-11-27 11:02  天蓝隐湘  阅读(476)  评论(0编辑  收藏  举报