基于Netty4.xx的客户端指数退避重试

指数退避重连: 每隔1秒,2秒,4秒, 8秒....以2的幂次来建立连接,到达一定次数之后放弃连接...

下面代码默认重试10次

直接上Netty客户端代码:

package org.jy.sso.websocket.stomp.push.netty.chat.system.client;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringEncoder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.time.DateFormatUtils;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * Netty基于异步事件驱动的高性能通信框架:
 * 客户端重连处理逻辑
 */
@Slf4j
public class NettyClient {
    // 最大重试次数
    private static final int MAX_RETRY_NUM = 10;
    // 重试初始值
    private static final int INI_RETRY_NUM = 0;
    // 步长
    private static final int STEP_RETRY_NUM_LENGTH = 1;

    // 连接的端口

    private static final int NETTY_SERVER_PORT = 8000;
    // 主机IP
    private static final String NETTY_SERVER_HOST_IP = "127.0.0.1";

    public static void main(String[] args) {
        Bootstrap bootstrap = new Bootstrap();
        NioEventLoopGroup group = new NioEventLoopGroup();
        bootstrap.group(group)
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<Channel>() {
                    @Override
                    protected void initChannel(Channel channel) {
                        // 注册字符串编码器
                        channel.pipeline().addLast(new StringEncoder());
                    }
                });
        connect(bootstrap, NETTY_SERVER_HOST_IP, NETTY_SERVER_PORT, MAX_RETRY_NUM);

    }

    /**
     * 
     *
     * @param bootstrap 客户端启动器
     * @param host      主机
     * @param port      端口
     * @param retryNum  指数退避重新连接的次数
     * @author yh19166
     * @deprecated 连接和重连机制,实现了指数退避重连
     */
    private static void connect(Bootstrap bootstrap, String host, int port, int retryNum) {
        bootstrap.connect(host, port).addListener(future -> {
            // 通过future.isSuccess() 判断是否连接成功
            if (future.isSuccess()) {
                System.out.println(DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss") + " -->> 连接成功....");
            } else if (retryNum == INI_RETRY_NUM) {
                System.out.println(DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss") + " -->> 重连次数已用完,放弃连接....");
            } else {
                // 第几次重连
                int order = (MAX_RETRY_NUM - retryNum) + STEP_RETRY_NUM_LENGTH;
                // 客户考虑重新连接的逻辑,分梯度连接......
                System.out.println("第 " + order + " 连接失败......");
                // 本次重连的间隔: 通过左移操作快速计算出重连时间间隔
                int delay = STEP_RETRY_NUM_LENGTH << order;
                System.out.println(DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss") + " -->> 连接失败,第" + order + "次重新连接....");
                // 实现定时任务逻辑
                bootstrap.config().group().schedule(() -> connect(bootstrap, host, port, retryNum - STEP_RETRY_NUM_LENGTH), delay, TimeUnit.SECONDS);
            }
        });
    }

    /**
     * @param bootstrap 客户端启动类
     * @param host      主机
     * @param port      端口
     * @param retryNum  指数退避重新连接的次数
     * @author yh19166
     * @deprecated 连接和重连机制,实现了指数退避重连
     */
    private static void retryConnect(Bootstrap bootstrap, String host, int port, int retryNum) {
        bootstrap.connect(host, port).addListener(future -> {
            if (future.isSuccess()) {
                log.info("连接服务器成功!");
            } else if (retryNum == INI_RETRY_NUM) {
                log.error("重连次数已用完,放弃连接!");
            } else {
                // 第几次重连
                int order = (MAX_RETRY_NUM - retryNum) + STEP_RETRY_NUM_LENGTH;
                // 本次重连的间隔
                int delay = STEP_RETRY_NUM_LENGTH << order;
                log.error(DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss") + ": 连接失败,第" + order + "次重新连接....");

                bootstrap.config().group().schedule(() -> connect(bootstrap, host, port, retryNum - STEP_RETRY_NUM_LENGTH), delay, TimeUnit.SECONDS);
            }
        });
    }

}

 基于Netty服务器端测试代码:

package org.jy.sso.websocket.stomp.push.netty.chat.system.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;

/**
 * 居于异步事件驱动高性能网络通信框架
 */
public class NettyServer {
    public static void main(String[] args) {
        // 服务器端启动类
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        // boss主线程(父线程)
        NioEventLoopGroup bossLoopGroup = new NioEventLoopGroup();
        // 工作线程(子线程)
        NioEventLoopGroup workerLoopGroup = new NioEventLoopGroup();
        serverBootstrap // 父子线程建立组连接
                .group(bossLoopGroup, workerLoopGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel ch) throws Exception {
                        // 初始化一个Channel(通道),pipeline(管道线)
                        // 字符串解码器
                        ch.pipeline().addLast(new StringDecoder());
                        ch.pipeline().addLast(new SimpleChannelInboundHandler<String>() {
                            @Override
                            protected void channelRead0(ChannelHandlerContext channelHandlerContext, String msg) throws Exception {
                                System.out.println("这是服务器端Netty接收到的消息: " + msg);
                            }
                        });

                    }
                }).bind(8000);
    }
}

测试结果:

11:17:38.131 [main] DEBUG io.netty.util.internal.logging.InternalLoggerFactory - Using SLF4J as the default logging framework
11:17:38.151 [main] DEBUG io.netty.channel.MultithreadEventLoopGroup - -Dio.netty.eventLoopThreads: 40
11:17:38.192 [main] DEBUG io.netty.util.internal.PlatformDependent0 - java.nio.Buffer.address: available
11:17:38.193 [main] DEBUG io.netty.util.internal.PlatformDependent0 - sun.misc.Unsafe.theUnsafe: available
11:17:38.194 [main] DEBUG io.netty.util.internal.PlatformDependent0 - sun.misc.Unsafe.copyMemory: available
11:17:38.195 [main] DEBUG io.netty.util.internal.PlatformDependent0 - direct buffer constructor: available
11:17:38.196 [main] DEBUG io.netty.util.internal.PlatformDependent0 - java.nio.Bits.unaligned: available, true
11:17:38.196 [main] DEBUG io.netty.util.internal.PlatformDependent0 - java.nio.DirectByteBuffer.<init>(long, int): available
11:17:38.197 [main] DEBUG io.netty.util.internal.Cleaner0 - java.nio.ByteBuffer.cleaner(): available
11:17:38.198 [main] DEBUG io.netty.util.internal.PlatformDependent - Platform: Windows
11:17:38.211 [main] DEBUG io.netty.util.internal.PlatformDependent - Java version: 8
11:17:38.211 [main] DEBUG io.netty.util.internal.PlatformDependent - -Dio.netty.noUnsafe: false
11:17:38.211 [main] DEBUG io.netty.util.internal.PlatformDependent - sun.misc.Unsafe: available
11:17:38.212 [main] DEBUG io.netty.util.internal.PlatformDependent - -Dio.netty.noJavassist: false
11:17:38.213 [main] DEBUG io.netty.util.internal.PlatformDependent - Javassist: unavailable
11:17:38.213 [main] DEBUG io.netty.util.internal.PlatformDependent - You don't have Javassist in your class path or you don't have enough permission to load dynamically generated classes.  Please check the configuration for better performance.
11:17:38.214 [main] DEBUG io.netty.util.internal.PlatformDependent - -Dio.netty.tmpdir: C:\Users\ADMINI~1\AppData\Local\Temp (java.io.tmpdir)
11:17:38.214 [main] DEBUG io.netty.util.internal.PlatformDependent - -Dio.netty.bitMode: 64 (sun.arch.data.model)
11:17:38.215 [main] DEBUG io.netty.util.internal.PlatformDependent - -Dio.netty.noPreferDirect: false
11:17:38.215 [main] DEBUG io.netty.util.internal.PlatformDependent - io.netty.maxDirectMemory: 15252586496 bytes
11:17:38.244 [main] DEBUG io.netty.channel.nio.NioEventLoop - -Dio.netty.noKeySetOptimization: false
11:17:38.244 [main] DEBUG io.netty.channel.nio.NioEventLoop - -Dio.netty.selectorAutoRebuildThreshold: 512
11:17:38.248 [main] DEBUG io.netty.util.internal.PlatformDependent - org.jctools-core.MpscChunkedArrayQueue: available
11:17:38.483 [main] DEBUG io.netty.channel.DefaultChannelId - -Dio.netty.processId: 16148 (auto-detected)
11:17:38.485 [main] DEBUG io.netty.util.NetUtil - -Djava.net.preferIPv4Stack: false
11:17:38.486 [main] DEBUG io.netty.util.NetUtil - -Djava.net.preferIPv6Addresses: false
11:17:39.809 [main] DEBUG io.netty.util.NetUtil - Loopback interface: lo (Software Loopback Interface 1, 127.0.0.1)
11:17:39.810 [main] DEBUG io.netty.util.NetUtil - \proc\sys\net\core\somaxconn: 200 (non-existent)
11:17:41.147 [main] DEBUG io.netty.channel.DefaultChannelId - -Dio.netty.machineId: 00:50:56:ff:fe:c0:00:01 (auto-detected)
11:17:41.149 [main] DEBUG io.netty.util.internal.ThreadLocalRandom - -Dio.netty.initialSeedUniquifier: 0xca7695bdb7e785ff
11:17:41.169 [main] DEBUG io.netty.util.ResourceLeakDetector - -Dio.netty.leakDetection.level: simple
11:17:41.169 [main] DEBUG io.netty.util.ResourceLeakDetector - -Dio.netty.leakDetection.maxRecords: 4
11:17:41.206 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.numHeapArenas: 40
11:17:41.206 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.numDirectArenas: 40
11:17:41.206 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.pageSize: 8192
11:17:41.206 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.maxOrder: 11
11:17:41.206 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.chunkSize: 16777216
11:17:41.206 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.tinyCacheSize: 512
11:17:41.206 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.smallCacheSize: 256
11:17:41.206 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.normalCacheSize: 64
11:17:41.206 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.maxCachedBufferCapacity: 32768
11:17:41.206 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.cacheTrimInterval: 8192
11:17:41.221 [main] DEBUG io.netty.buffer.ByteBufUtil - -Dio.netty.allocator.type: pooled
11:17:41.221 [main] DEBUG io.netty.buffer.ByteBufUtil - -Dio.netty.threadLocalDirectBufferSize: 65536
11:17:41.221 [main] DEBUG io.netty.buffer.ByteBufUtil - -Dio.netty.maxThreadLocalCharBufferSize: 16384
第 1 连接失败......
2023-05-21 11:17:42 -->> 连接失败,第1次重新连接....
第 2 连接失败......
2023-05-21 11:17:45 -->> 连接失败,第2次重新连接....
第 3 连接失败......
2023-05-21 11:17:50 -->> 连接失败,第3次重新连接....
第 4 连接失败......
2023-05-21 11:17:59 -->> 连接失败,第4次重新连接....
第 5 连接失败......
2023-05-21 11:18:16 -->> 连接失败,第5次重新连接....
第 6 连接失败......
2023-05-21 11:18:49 -->> 连接失败,第6次重新连接....
第 7 连接失败......
2023-05-21 11:19:54 -->> 连接失败,第7次重新连接....
2023-05-21 11:22:02 -->> 连接成功....

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值