netty心跳检测

一 什么是心跳检测机制

心跳是指,在TCP长连接中 客户端和服务端定期的互相发送数据包, 这样可以确保服务的正确运行,保证服务在线和TCP长连接的可靠性;通常的心跳实现机制是客户端定期的向服务端发送数据包,服务端接收到数据后进行应答,这样就保证了TCP的长连接;当然也有做法是服务端做心跳,如果客户端没有应答,就关闭对应的连接,节省资源,但是这种情况毕竟罕见!

二 netty 心跳工作原理

netty 中 进行实现心跳机制是,当客户端写空闲时就可以向服务端发送数据包,服务端收到心跳包后进行回复;关键点就是如何判定 客户端 是处于写空闲状态;netty中提供了 IdleStateHandler 的处理器;可以监听通道的读写状态;

  1. readerIdleTime表示 读超时
  2. writerIdleTime 表示写超时
  3. allIdleTime 表示 读写超时
  4. unit 表示 时间单位
public IdleStateHandler(long readerIdleTime, long writerIdleTime, long allIdleTime, TimeUnit unit) {
        this(false, readerIdleTime, writerIdleTime, allIdleTime, unit);
    }

三 netty 客户端实现心跳机制

在 客户端连接时启动加入 监听事件
pipeline.addLast("ping", new IdleStateHandler(30, 20, 90, TimeUnit.SECONDS));

表示 读 30 秒空闲, 写 20 秒空闲;读写 90 秒空闲

 public void connect(int port, String host) throws InterruptedException {

        // 创建线程组
        NioEventLoopGroup nioEventLoopGroup = new NioEventLoopGroup();
        // netty启动辅助类
        Bootstrap bootstrap = new Bootstrap();
        //
        bootstrap.group(nioEventLoopGroup)
                .channel(NioSocketChannel.class)
                .option(ChannelOption.TCP_NODELAY, true)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        // 处理IO事件
                        ChannelPipeline pipeline = socketChannel.pipeline();
                        // 心跳检测
                        pipeline.addLast("ping", new IdleStateHandler(30, 20, 90, TimeUnit.SECONDS));
                        pipeline.addLast(new StringEncoder());
                        pipeline.addLast(new StringDecoder());
                        //
                        pipeline.addLast(new NettyClientHandler());

                    }
                });
        // 异步操作
        ChannelFuture connect = bootstrap.connect(host, port).sync();
        // 关闭客户端
        connect.channel().closeFuture().sync();
        // 退出线程组
        nioEventLoopGroup.shutdownGracefully();
    }

然后 在处理器中 实现 userEventTriggered 方法对当前的通道状态进行判定,然后根据不同的状态发送心跳包;在客户端我们只需要是写空闲的时候发送心跳包即可;

@Slf4j
public class NettyClientHandler extends ChannelInboundHandlerAdapter {




    public NettyClientHandler() {
        super();
    }

    // ......

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent e = (IdleStateEvent) evt;
            switch (e.state()) {
                case READER_IDLE:
                    System.out.println("读空闲");
                    break;
                case WRITER_IDLE:
                    // 写空闲,发送心跳
                    System.out.println("写空闲,发送心跳包");
                    ctx.writeAndFlush("1");
                    break;
                case ALL_IDLE:
                    System.out.println("读写空闲");
                    break;
                default:
                    break;
            }
        }
        super.userEventTriggered(ctx, evt);
    }
}

在测试代码中,客户端发送心跳包 1; 服务端回复 0;

客户端效果图如下

服务端效果图如下

本套教程

posted @ 2021-03-10 17:19  知识追寻者  阅读(597)  评论(0编辑  收藏  举报