zoukankan      html  css  js  c++  java
  • 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;

    客户端效果图如下

    服务端效果图如下

    本套教程

  • 相关阅读:
    419. Battleships in a Board
    150. Evaluate Reverse Polish Notation
    153. Find Minimum in Rotated Sorted Array
    319. Bulb Switcher
    223. Rectangle Area
    iOS 常用到的宏#define
    VRAR 使用 SceneKit
    VR、AR、MR定义区别
    Swift 开源项目练习应用
    Swift3.0 UITextField
  • 原文地址:https://www.cnblogs.com/zszxz/p/14512996.html
Copyright © 2011-2022 走看看