从零开始实现简单 RPC 框架 9:网络通信之心跳与重连机制

本文从零开始介绍如何实现简单的RPC框架,重点讲解了心跳和重连机制。通过Netty的IdleStateHandler处理心跳事件,客户端和服务端的心跳实现,以及重连机制的工作原理。这些机制保证了TCP连接的有效性和服务的高可用性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、心跳

什么是心跳

在 TPC 中,客户端和服务端建立连接之后,需要定期发送数据包,来通知对方自己还在线,以确保 TPC 连接的有效性。如果一个连接长时间没有心跳,需要及时断开,否则服务端会维护很多无用连接,浪费服务端的资源。

IdleStateHandler

Netty 已经为我们提供了心跳的 Handler:IdleStateHandler。当连接的空闲时间(读或者写)太长时,IdleStateHandler 将会触发一个 IdleStateEvent 事件,传递的下一个 Handler。我们可以通过在 Pipeline Handler 中重写 userEventTrigged 方法来处理该事件,注意我们自己的 Handler 需要在 IdleStateHandler 后面。

下面我们来看看 IdleStateHandler 的源码。

1. 构造函数

最完整的构造函数如下:

public IdleStateHandler(boolean observeOutput,
            long readerIdleTime, long writerIdleTime, long allIdleTime,
            TimeUnit unit) {
   
}

参数解析:

  • observeOutput:是否考虑出站时较慢的情况。如果 true:当出站时间太长,超过空闲时间,那么将不触发此次事件。如果 false,超过空闲时间就会触发事件。默认 false。
  • readerIdleTime:读空闲的时间,0 表示禁用读空闲事件。
  • writerIdleTime:写空闲的时间,0 表示禁用写空闲事件。
  • allIdleTime:读或写空闲的时间,0 表示禁用事件。
  • unit:前面三个时间的单位。
2. 事件处理

IdleStateHandler 继承 ChannelDuplexHandler,重写了出站和入站的事件,我们来看看代码。
当 channel 添加、注册、活跃的时候,会初始化 initialize(ctx),删除、不活跃的时候销毁 destroy(),读写的时候设置 lastReadTimelastWriteTime 字段。

public class IdleStateHandler extends ChannelDuplexHandler {
   

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
   
        if (ctx.channel().isActive() && ctx.channel().isRegistered()) {
   
            initialize(ctx);
        }
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
   
        destroy();
    }

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
   
        if (ctx.channel().isActive()) {
   
            initialize(ctx);
        }
        super.channelRegistered(ctx);
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
   
        initialize(ctx);
        super.channelActive(ctx);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
   
        destroy();
        super.channelInactive(ctx);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
   
        // 判断是否开启 读空闲 或者 读写空闲 监控
        if (readerIdleTimeNanos > 0 || allIdleTimeNanos > 0) {
   
            // 设置 reading 标志位
            reading = true;
            firstReaderIdleEvent = firstAllIdleEvent = true;
        }
        ctx.fireChannelRead(msg);
    }

    // 读完成之后
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
   
        // 判断是否开启 读空闲 或者 读写空闲 监控,检查 reading 标志位
        if ((readerIdleTimeNanos > 0 || allIdleTimeNanos > 0) && reading) {
   
            // 设置 lastReadTime,后面判断读超时有用
            lastRe
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值