Netty心跳检测代码实例及源码分析

2020-08-04  本文已影响0人  Zak1

背景:今天在研读项目netty相关代码时,发现有设备有心跳机制(尽管在本项目中没啥左右),本着要不试一下的方式,调用下Netty提供的IdleStatHandler这个handler来实现一下心跳检测功能。

  1. 在网上搜索了一下netty的心跳检测api,光看到IdleStatHandler就直接下手写代码了,想着也就一套调用链的方式,写完测一下没问题就ok了,便写下了如下代码:

    Netty服务端代码:

    public class MyServer {
        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(new LoggingHandler(LogLevel.INFO)) 
                        .childHandler(new ChannelInitializer<SocketChannel>() {
                            @Override
                            protected void initChannel(SocketChannel ch) throws Exception {
                                ChannelPipeline channelPipeline = ch.pipeline();
                                channelPipeline.addLast(new HeartBeatHandler(3, 0, 0));
                                channelPipeline.addLast(new MyServerHandler());
                     
                            }
                        });
    
    
                ChannelFuture channelFuture = serverBootstrap.bind(10005).sync();
                channelFuture.channel().closeFuture().sync();
    
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                bossGroup.shutdownGracefully();
                workerGroup.shutdownGracefully();
            }
        }
    }
    ------------------------------------------------------------------------
    public class HeartBeatHandler  extends IdleStateHandler {
        public HeartBeatHandler(int readerIdleTimeSeconds, int writerIdleTimeSeconds, int allIdleTimeSeconds) {
            super(readerIdleTimeSeconds, writerIdleTimeSeconds, allIdleTimeSeconds);
        }
        @Override
        public void read(ChannelHandlerContext ctx) throws Exception {
            System.out.println("HeartBeatHandler----->"+ctx);
            super.read(ctx);
        }
    
        @Override
        public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
            System.out.println("HeartBeatHandler 中的userEventTriggered被触发");
            //空闲状态转换
            if (evt instanceof IdleStateEvent) {
                IdleStateEvent idleStateEvent = (IdleStateEvent) evt;
                String evenType = null;
    
                switch (idleStateEvent.state()) {
                    case READER_IDLE:
                        evenType = "读空闲";
                        break;
                    case WRITER_IDLE:
                        evenType = "写空闲";
                        break;
                    case ALL_IDLE:
                        evenType = "读写空闲";
                        break;
                }
                System.out.println(ctx.channel().remoteAddress() + "超时事件:" + evenType);
            }
        }
    }
    ---------------------------
    public class MyServerHandler extends ChannelInboundHandlerAdapter {
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            System.out.println(msg);
            super.channelRead(ctx, msg);
        }
    }
    

    Socket测试代码:

    public class Test {
        public static void socketTest() throws IOException, InterruptedException {
            Socket socket=new Socket("127.0.0.1",10005);
            PrintWriter pw = new PrintWriter(socket.getOutputStream());
            for (int i=0;i<100;i++){
                pw.println("HelloWorld");
                pw.flush();
                TimeUnit.SECONDS.sleep(5);
            }
            pw.close();
            socket.close();
        }
        public static void main(String[] args) throws IOException, InterruptedException {
            socketTest();
        }
    }
    
    1. 开始自信的运行代码,结果发现光顾着输出helloworld相关的内容了(为什么不直接是helloWorld,因为这里没有做编解码操作,这不是本文讨论重点)

    2. 尝试百度,stackoverflow,也没能查到原由,也没能看到示例代码,基本给的解决方案都是指将IdlestatHandler调用链放置在第一位置(我本来就这样放的ORZ),顺便吐槽一下csdn : )

ChannelPipeline handler调用图:

*  +---------------------------------------------------+---------------+
*  |                           ChannelPipeline         |               |
*  |                                                  \|/              |
*  |    +---------------------+            +-----------+----------+    |
*  |    | Inbound Handler  N  |            | Outbound Handler  1  |    |
*  |    +----------+----------+            +-----------+----------+    |
*  |              /|\                                  |               |
*  |               |                                  \|/              |
*  |    +----------+----------+            +-----------+----------+    |
*  |    | Inbound Handler N-1 |            | Outbound Handler  2  |    |
*  |    +----------+----------+            +-----------+----------+    |
*  |              /|\                                  .               |
*  |               .                                   .               |
*  | ChannelHandlerContext.fireIN_EVT() ChannelHandlerContext.OUT_EVT()|
*  |        [ method call]                       [method call]         |
*  |               .                                   .               |
*  |               .                                  \|/              |
*  |    +----------+----------+            +-----------+----------+    |
*  |    | Inbound Handler  2  |            | Outbound Handler M-1 |    |
*  |    +----------+----------+            +-----------+----------+    |
*  |              /|\                                  |               |
*  |               |                                  \|/              |
*  |    +----------+----------+            +-----------+----------+    |
*  |    | Inbound Handler  1  |            | Outbound Handler  M  |    |
*  |    +----------+----------+            +-----------+----------+    |
*  |              /|\                                  |               |
*  +---------------+-----------------------------------+---------------+
*                  |                                  \|/
*  +---------------+-----------------------------------+---------------+
*  |               |                                   |               |
*  |       [ Socket.read() ]                    [ Socket.write() ]     |
*  |                                                                   |
*  |  Netty Internal I/O Threads (Transport Implementation)            |
*  +-------------------------------------------------------------------+
上一篇下一篇

猜你喜欢

热点阅读