Netty系列文章 - 心跳检测

Itachi 2020年01月03日 169次浏览

Netty系列文章 - 心跳检测

本章暂且先不讨论Netty源码是怎么实现的,先看一下Netty心跳检测的应用.

科普基础

  1. 心跳机制
    • 心跳是在TCP长连接中,客户端和服务端定时向对方发送数据包通知对方自己还在线,保证连接的有效性的一种机制
    • 在服务器和客户端之间一定时间内没有数据交互时, 即处于 idle 状态时, 客户端或服务器会发送一个特殊的数据包给对方, 当接收方收到这个数据报文后, 也立即发送一个特殊的数据报文, 回应发送方, 此即一个 PING-PONG 交互. 自然地, 当某一端收到心跳消息后, 就知道了对方仍然在线, 这就确保 TCP 连接的有效性
  2. 心跳实现
    • 使用TCP协议层的Keeplive机制,但是该机制默认的心跳时间是2小时,依赖操作系统实现不够灵活
    • 应用层实现自定义心跳机制,比如Netty实现心跳机制

快速开始

Server

/**
 * @author Itachi is.xianglei@gmail.com
 * @Date 2020-01-03 15:56
 */
public class Server {
    @SneakyThrows
    public static void main(String[] args) {
        // 主线程
        EventLoopGroup master = new NioEventLoopGroup(1);
        // 工作线程
        EventLoopGroup slave = new NioEventLoopGroup();
        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(master,slave)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        ChannelPipeline pipeline = ch.pipeline();
                        pipeline.addLast(new StringDecoder(Charset.defaultCharset()));

                        pipeline.addLast(new DelimiterBasedFrameDecoder(4096, Delimiters.lineDelimiter()));

                        /**
                         * 10: 10秒后进入读空闲
                         * 15: 15秒后进入写空闲
                         * 30: 30秒后进入读写空闲
                         */
                        pipeline.addLast(new IdleStateHandler(10,15,30, TimeUnit.SECONDS));

                        /**
                         * 自定义的心跳检测处理器
                         */
                        pipeline.addLast(new HeartBeatHandler());

                        /**
                         * 自定义的消息处理器
                         */
                        pipeline.addLast(new MyHandler());
                    }
                });
        ChannelFuture channelFuture = bootstrap.bind("127.0.0.1", 9090).sync();
        channelFuture.channel().closeFuture();
    }

}

MyHandler

/**
 * @author Itachi is.xianglei@gmail.com
 * @Date 2020-01-03 16:06
 */
public class MyHandler extends SimpleChannelInboundHandler<String> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        Channel channel = ctx.channel();
        SocketAddress socketAddress = channel.remoteAddress();
        System.out.println(socketAddress + "->发来消息: "+msg);
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        SocketAddress socketAddress = ctx.channel().remoteAddress();
        System.out.println(socketAddress+"<-已上线!");
    }
}

HeartBeatHandler

/**
 * @author Itachi is.xianglei@gmail.com
 * @Date 2020-01-03 16:32
 */
public class HeartBeatHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;

            // 读空闲
            if (IdleState.READER_IDLE == event.state()) {
                System.out.println("进入读空闲...");
            }

            // 写空闲
            if (IdleState.WRITER_IDLE == event.state()) {
                System.out.println("进入写空闲...");
            }

            // 读写空闲
            if (IdleState.ALL_IDLE == event.state()) {
                System.out.println("进入读写空闲,即将断开与客户端连接...");
                ctx.channel().close();
                System.out.println("断开连接!");
            }

        }
    }
}

客户端连接工具

image.png 推测: 在我们配置的读写时间内.我们客户端不往服务端发送数据,超过10秒,就会进入读空闲.

服务端不往客户端发送数据超过15秒就会进入写空闲, 在30秒内,不写不读的情况下..会一直进行心跳检测..

超过30秒后则会进入读写空闲,并关闭客户端的连接..

控制台输出

image.png

如有疑问,欢迎留言.