Skip to content

6 Heartbeat

BladeCode edited this page Nov 23, 2019 · 1 revision

服务器上的集群服务(zookeeper 或者其他的应用服务),或者是客户端与服务端之间的长连接

  • 对于服务器上的这些服务与服务之间,节点与节点之间的通信(无一例外都使用 TCP 连接通信),节点之间的通信如何保证(A 节点感知到 B 或者其他节点是未宕机),此时就需要心跳来检测对应的服务或节点还是正常的
  • 对于客户端与服务器之间由于网络问题,或者客户端开启飞行模式,或者关机等状态,服务端是无法感知,因此也需要借助心跳来检测客户端是否关机或开启了飞行模式

通过下面的示例,来学习 Netty 相关的心跳处理

服务端

服务启动类,程序入口

public static void main(String[] args) throws InterruptedException {
    EventLoopGroup bossGroup = new NioEventLoopGroup();
    EventLoopGroup workerGroup = new NioEventLoopGroup();

    try {
        // handler() 与 childHandler() 的区别
        // 服务端可以使用 handler() 或者 childHandler(),而对于客户端,一般只使用handler()
        // handler()对于处理的 bossGroup 相关的信息,比如链接后,输出日志
        // childHandler() 是指连接丢给 workerGroup 之后,对 workerGroup 的 NIO 线程作用
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        serverBootstrap.group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .handler(new LoggingHandler(LogLevel.INFO))
                .childHandler(new HeartbeatServerInitializer());
        ChannelFuture channelFuture = serverBootstrap.bind(4321).sync();
        channelFuture.channel().closeFuture().sync();
    } finally {
        bossGroup.shutdownGracefully();
        workerGroup.shutdownGracefully();
    }
}

自定义服务初始化

@Override
protected void initChannel(SocketChannel ch) throws Exception {
    ChannelPipeline pipeline = ch.pipeline();
    // netty 提供的一个空闲状态检查的 handler(IdleStateHandler)
    pipeline.addLast(new IdleStateHandler(5, 7, 10, TimeUnit.SECONDS));
    // 自定义服务处理器
    pipeline.addLast("HeartbeatServerHandler", new HeartbeatServerHandler());
}
public class HeartbeatServerHandler extends ChannelInboundHandlerAdapter {

    /**
     * 触发某一个事件后被调用
     *
     * @param ctx 通道处理上下文
     * @param evt 事件
     * @throws Exception 异常
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            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;
                default:
                    break;
            }

            System.out.println(ctx.channel().remoteAddress() + "超时事件:" + eventType);
            ctx.channel().closeFuture();
        }
    }
}

客户端

可直接使用 Socket 中的客户端代码

Clone this wiki locally