admin管理员组文章数量:1608624
Netty网络框架学习笔记-17(客户端断线重连_2022-06-27)
使用网络编程, 就不可避免客户端存在, 断网, 设备断电, 导致客户端与服务端的连接中断, 在或者启动时候就失败了!
所以需要有重连机制
netty
的重连本质上就是在调多一次bootstrap.connect(remoteAddress).sync()
1.0 最简单的固定间隔时间重连 (不建议使用)
客户端连接成功后, 当前连接线程会阻塞,
当客户端连接失败, 会抛出一个
ConnectException
异常, 当拦截到这个异常就开启重连
public static void main(String[] args) {
NioEventLoopGroup workerGroup = new NioEventLoopGroup();
Bootstrap bootstrap = new Bootstrap();
bootstrap = bootstrap.group(workerGroup)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
//..........省略
}
});
InetSocketAddress remoteAddress = new InetSocketAddress("127.0.0.1", 8888);
// 重试次数
int retryCount = 100;
// 一个条件死循环, 里面第一步会不断的连接服务端
for (; ; ) {
try {
ChannelFuture channelFuture = bootstrap.connect(remoteAddress).sync();
channelFuture.channel().closeFuture().sync();
} catch (Exception e) {
// 当是连接异常时候, 继续循环
if (e instanceof ConnectException){
retryCount--;
log.error("NettyTcpClient-发生异常, 信息:", e);
ThreadUtil.sleep(15, TimeUnit.SECONDS);
}else {
break;
}
}
// 重试到达100次数则不在重试 , 或者可以自定义次数, 或者可以无限每隔15秒重试一次
if (retryCount <= 0) {
break;
}
}
// 关闭线程组
workerGroup.shutdownGracefully();
}
上面这种方法很简单, 也有缺点, 有可能客户端第一次启动, 连接地址写错了, 但确实有这个地址, 也可能会报
ConnectException
异常, 也会一直触发重连, 而且由于连接地址是错误的 , 所以会一直连接不上。 所以这种方法不建议使用。如果非要使用, 得配置, 连接失败时候, 会通知开发人员, 例如: 钉钉、 电话、 邮件等通知
2.0 建议使用方式,
这个方式, 本质是已经在建立连接成功后, 使用netty提供的处理器事件, 当通道不活跃的时候触发的事件
channelInactive(ChannelHandlerContext ctx)
里面进行重试连接。
2.1.1 重试策略类RetryStrategy
/**
* @Author: ZhiHao
* @Date: 2022/6/27 16:31
* @Description:
* @Versions 1.0
**/
@Slf4j
public class RetryStrategy {
// 启动引导类
private Bootstrap bootstrap;
// 最大重试次数
private Integer retryMaxCount = Integer.MAX_VALUE;
// 最长间隔重试时间
private Integer retryMaxTime = 60;
// 每次重试增加多少秒
private Integer retryAddTime = 0;
// 重试成功触发的事件
private Consumer<Boolean> consumer;
// 初始重试次数
private int currentRetryCount = 0;
// 初始重试间隔 1秒
private long delay = 1L;
public Bootstrap buildBootstrapAndReturnBootstrap(Bootstrap bootstrap) {
this.bootstrap = bootstrap;
return bootstrap;
}
public void setRetryMaxCount(Integer retryMaxCount) {
this.retryMaxCount = retryMaxCount;
}
public void setRetryMaxTime(Integer retryMaxTime) {
this.retryMaxTime = retryMaxTime;
}
public void setRetryAddTime(Integer retryAddTime) {
this.retryAddTime = retryAddTime;
}
public void setConsumer(Consumer<Boolean> consumer) {
this.consumer = consumer;
}
public void processRetryConnect(ChannelHandlerContext ctx) {
if (Objects.isNull(ctx)){
log.error("RetryStrategy===处理器都不存在!!!");
// 关闭整个客户端, 是整个netty应用停止
bootstrap.config().group().shutdownGracefully();
return;
}
if (currentRetryCount >= retryMaxCount) {
log.error("RetryStrategy===重试已达最大次数, 取消重试, 关闭客户端!!!");
// 关闭整个客户端, 是整个netty应用停止
bootstrap.config().group().shutdownGracefully();
return;
}
long delay = this.getDelay();
EventLoop eventLoop = ctx.channel().eventLoop();
eventLoop.schedule(() -> {
try {
currentRetryCount++;
long delayTime = this.delay;
int count = this.currentRetryCount;
ChannelFuture channelFuture = bootstrap.connect();
channelFuture.addListener(future -> {
// 触发事件
boolean futureSuccess = future.isSuccess();
// 失败后重调递归调
if (!futureSuccess) {
this.processRetryConnect(ctx);
} else {
// 成功后重置次数和延迟时间
this.currentRetryCount = 0;
this.delay = 0L;
Optional.ofNullable(consumer).ifPresent(el -> el.accept(Boolean.TRUE));
}
log.info("===RetryStrategy===, 重连, 当前次数:{}, 当前延迟重试间隔:{}秒, 重试结果:{}", count, delay, futureSuccess);
});
channelFuture.sync();
} catch (Exception e) {
log.error("NettyRetryClientHandle====重连失败, 原因: ", e);
}
}, delay, TimeUnit.SECONDS);
// 传递给下一个处理器
ctx.fireChannelInactive();
}
private long getDelay() {
if (delay >= retryMaxTime) {
return retryMaxTime;
}
if (currentRetryCount != 0) {
delay += retryAddTime;
}
return delay;
}
}
2.1.2 自定义重试处理器
@Slf4j
public class NettyRetryClientHandle extends ChannelInboundHandlerAdapter {
private RetryStrategy retryStrategy;
public NettyRetryClientHandle(RetryStrategy retryStrategy) {
this.retryStrategy = retryStrategy;
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
log.error("NettyRetryClientHandle===触发通道不活跃, 进行重连!");
retryStrategy.setConsumer(el->{
log.info("NettyRetryClientHandle===重连成功, 触发做自己的事情!!!!!!!");
});
retryStrategy.processRetryConnect(ctx);
}
}
2.1.3 客户端
@Slf4j
public class NettyRetryClientTwo {
public static void main(String[] args) {
NioEventLoopGroup workerGroup = new NioEventLoopGroup();
RetryStrategy retryStrategy = new RetryStrategy();
retryStrategy.setRetryAddTime(1);
retryStrategy.setRetryMaxCount(3);
Bootstrap bootstrap = retryStrategy.buildBootstrapAndReturnBootstrap(new Bootstrap());
bootstrap = bootstrap.group(workerGroup)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
pipeline.addLast(new NettyTcpClientHandle());
// 添加自定义重试连接处理器
pipeline.addLast(new NettyRetryClientHandle(retryStrategy));
}
});
bootstrap.remoteAddress(new InetSocketAddress("127.0.0.1", 8888));
//bootstrap.remoteAddress(new InetSocketAddress("47.119.137.321", 3306));
try {
ChannelFuture channelFuture = bootstrap.connect();
// 添加监听, 最初启动时候是否成功!
channelFuture.addListener(el->{
// 失败则进行重试!
if (!el.isSuccess()) {
ChannelHandlerContext context = channelFuture.channel().pipeline().context(NettyRetryClientHandle.class);
retryStrategy.processRetryConnect(context);
}else {
log.error("NettyTcpClient-启动成功了!!!");
}
});
channelFuture.sync().channel().closeFuture().sync();
} catch (Exception e) {
log.error("NettyTcpClient-发生异常, 信息:", e);
}
}
}
2.1 进行测试, 客户端一启动就报错
## 一直重试到最大次数都没有成功, 关闭客户端!
18:20:03.786 [nioEventLoopGroup-2-1] ERROR com.zhihaoty.clientRetryConnect.NettyRetryClientTwo - NettyTcpClient-启动就连接失败了, 进行重试!!!
18:20:03.786 [main] ERROR com.zhihaoty.clientRetryConnect.NettyRetryClientTwo - NettyTcpClient-发生异常, 信息:
ioty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: no further information: /127.0.0.1:8888
Caused by: java.ConnectException: Connection refused: no further information
18:20:06.833 [nioEventLoopGroup-2-1] ERROR com.zhihaoty.clientRetryConnect.RetryStrategy - NettyRetryClientHandle====重连失败, 原因:
ioty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: no further information: /127.0.0.1:8888
Caused by: java.ConnectException: Connection refused: no further information
18:20:06.833 [nioEventLoopGroup-2-2] INFO com.zhihaoty.clientRetryConnect.RetryStrategy - ===RetryStrategy===, 当前次数:1, 当前延迟重试间隔:1秒, 重试结果:false
18:20:10.886 [nioEventLoopGroup-2-3] INFO com.zhihaoty.clientRetryConnect.RetryStrategy - ===RetryStrategy===, 当前次数:2, 当前延迟重试间隔:2秒, 重试结果:false
18:20:10.886 [nioEventLoopGroup-2-1] ERROR com.zhihaoty.clientRetryConnect.RetryStrategy - NettyRetryClientHandle====重连失败, 原因:
ioty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: no further information: /127.0.0.1:8888
Caused by: java.ConnectException: Connection refused: no further information
18:20:15.947 [nioEventLoopGroup-2-4] ERROR com.zhihaoty.clientRetryConnect.RetryStrategy - RetryStrategy===重试已达最大次数, 取消重试, 关闭客户端!!!
18:20:15.947 [nioEventLoopGroup-2-1] ERROR com.zhihaoty.clientRetryConnect.RetryStrategy - NettyRetryClientHandle====重连失败, 原因:
ioty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: no further information: /127.0.0.1:8888
Caused by: java.ConnectException: Connection refused: no further information
18:20:15.948 [nioEventLoopGroup-2-4] INFO com.zhihaoty.clientRetryConnect.RetryStrategy - ===RetryStrategy===, 当前次数:3, 当前延迟重试间隔:3秒, 重试结果:false
### -----------------------------------------------------------------------------------------------------
### 重试成功!
18:29:50.378 [nioEventLoopGroup-2-1] ERROR com.zhihaoty.clientRetryConnect.NettyRetryClientTwo - NettyTcpClient-启动就连接失败了, 进行重试!!!
18:29:50.379 [main] ERROR com.zhihaoty.clientRetryConnect.NettyRetryClientTwo - NettyTcpClient-发生异常, 信息:
ioty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: no further information: /127.0.0.1:8888
Caused by: java.ConnectException: Connection refused: no further information
18:29:53.437 [nioEventLoopGroup-2-1] ERROR com.zhihaoty.clientRetryConnect.RetryStrategy - NettyRetryClientHandle====重连失败, 原因:
ioty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: no further information: /127.0.0.1:8888
Caused by: java.ConnectException: Connection refused: no further information
18:29:53.437 [nioEventLoopGroup-2-2] INFO com.zhihaoty.clientRetryConnect.RetryStrategy - ===RetryStrategy===, 当前次数:1, 当前延迟重试间隔:1秒, 重试结果:false
18:29:57.488 [nioEventLoopGroup-2-3] INFO com.zhihaoty.clientRetryConnect.RetryStrategy - ===RetryStrategy===, 当前次数:2, 当前延迟重试间隔:2秒, 重试结果:false
18:29:57.488 [nioEventLoopGroup-2-1] ERROR com.zhihaoty.clientRetryConnect.RetryStrategy - NettyRetryClientHandle====重连失败, 原因:
ioty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: no further information: /127.0.0.1:8888
Caused by: java.ConnectException: Connection refused: no further information
18:30:01.007 [nioEventLoopGroup-2-4] INFO com.zhihaoty.clientRetryConnect.RetryStrategy - ===RetryStrategy===, 当前次数:3, 当前延迟重试间隔:3秒, 重试结果:true
18:30:01.021 [nioEventLoopGroup-2-4] DEBUG ioty.util.Recycler - -Dioty.recycler.maxCapacityPerThread: 4096
18:30:01.021 [nioEventLoopGroup-2-4] DEBUG ioty.util.Recycler - -Dioty.recycler.ratio: 8
18:30:01.021 [nioEventLoopGroup-2-4] DEBUG ioty.util.Recycler - -Dioty.recycler.chunkSize: 32
18:30:01.030 [nioEventLoopGroup-2-4] DEBUG ioty.buffer.AbstractByteBuf - -Dioty.buffer.checkAccessible: true
18:30:01.030 [nioEventLoopGroup-2-4] DEBUG ioty.buffer.AbstractByteBuf - -Dioty.buffer.checkBounds: true
18:30:01.031 [nioEventLoopGroup-2-4] DEBUG ioty.util.ResourceLeakDetectorFactory - Loaded default ResourceLeakDetector: ioty.util.ResourceLeakDetector@a6737b0
18:30:01.089 [nioEventLoopGroup-2-4] INFO com.zhihaoty.tcp.NettyTcpClientHandle - NettyTcpClientHandle-读取到信息:74e0c2f2-c993-4831-bc62-31f709946538b508fa6f-a884-471c-994b-85179bb21a7128d57d14-a5bc-4205-8476-35d511bcaffa8096b5d0-5f7a-411a-b96d-46a1405c992823f0090e-61d0-423c-80c6-26afc46c359f
18:30:01.089 [nioEventLoopGroup-2-4] INFO com.zhihaoty.tcp.NettyTcpClientHandle - NettyTcpClientHandle-读取到多少次信息:1
2.2 进行测试, 网络波动或者中途断连
18:33:11.642 [nioEventLoopGroup-2-1] ERROR com.zhihaoty.clientRetryConnect.NettyRetryClientTwo - NettyTcpClient-启动成功了!!!
18:33:11.644 [nioEventLoopGroup-2-1] INFO com.zhihaoty.tcp.NettyTcpClientHandle - NettyTcpClientHandle-读取到信息:2e0ad20d-81a4-4a76-8065-259a57e247ff5e587c61-c96a-45d3-81d5-dd69dcd94f1457700452-3074-4bd6-be94-b862842a098104963210-7f46-40eb-9fb1-00a7d02918aa6e43e648-e965-474f-a319-bdf155f4a7bc
18:33:11.644 [nioEventLoopGroup-2-1] INFO com.zhihaoty.tcp.NettyTcpClientHandle - NettyTcpClientHandle-读取到多少次信息:1
18:33:35.399 [nioEventLoopGroup-2-1] ERROR com.zhihaoty.clientRetryConnect.NettyRetryClientHandle - NettyRetryClientHandle===触发通道不活跃, 进行重连!
18:33:38.451 [nioEventLoopGroup-2-2] INFO com.zhihaoty.clientRetryConnect.RetryStrategy - ===RetryStrategy===, 当前次数:1, 当前延迟重试间隔:1秒, 重试结果:false
18:33:38.452 [nioEventLoopGroup-2-1] ERROR com.zhihaoty.clientRetryConnect.RetryStrategy - NettyRetryClientHandle====重连失败, 原因:
ioty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: no further information: /127.0.0.1:8888
Caused by: java.ConnectException: Connection refused: no further information
18:33:42.512 [nioEventLoopGroup-2-3] INFO com.zhihaoty.clientRetryConnect.RetryStrategy - ===RetryStrategy===, 当前次数:2, 当前延迟重试间隔:2秒, 重试结果:false
18:33:42.512 [nioEventLoopGroup-2-1] ERROR com.zhihaoty.clientRetryConnect.RetryStrategy - NettyRetryClientHandle====重连失败, 原因:
ioty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: no further information: /127.0.0.1:8888
Caused by: java.ConnectException: Connection refused: no further information
18:33:46.524 [nioEventLoopGroup-2-4] INFO com.zhihaoty.clientRetryConnect.NettyRetryClientHandle - NettyRetryClientHandle===重连成功, 触发做自己的事情!!!!!!!
18:33:46.525 [nioEventLoopGroup-2-4] INFO com.zhihaoty.clientRetryConnect.RetryStrategy - ===RetryStrategy===, 当前次数:3, 当前延迟重试间隔:3秒, 重试结果:true
18:33:46.584 [nioEventLoopGroup-2-4] INFO com.zhihaoty.tcp.NettyTcpClientHandle - NettyTcpClientHandle-读取到信息:fe3de0ab-6c65-45bd-8852-0f92805bb23d
18:33:46.584 [nioEventLoopGroup-2-4] INFO com.zhihaoty.tcp.NettyTcpClientHandle - NettyTcpClientHandle-读取到多少次信息:8
总结:
第一种方式使用场景有限!
第二种方式, 可以自定义扩展的情况更全一点!!!
1
版权声明:本文标题:Netty网络框架学习笔记-17(客户端断线重连) 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://www.elefans.com/xitong/1728549909a1163297.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论