1. 背景
网络抖动可能导致TCP断联,或者服务端的心跳机制关闭连接了,这个时候由于连接都是客户端发起的,我们需要从客户端再次发起重连,首先得感知到TCP连接的状态,才能决定要不要发起重连
2. 代码
@Slf4j
public class NettyClient {
private Bootstrap bootstrap = null;
private int failedCount = 0;
public void initClient() throws InterruptedException {
EventLoopGroup group = new NioEventLoopGroup();
bootstrap = new Bootstrap();
//设置相关参数
bootstrap.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) {
ch.pipeline().addLast(new NettyClientHandler(NettyClient.this));
}
});
connect();
}
public static void main(String[] args) throws InterruptedException {
new NettyClient().initClient();
}
public void connect() throws InterruptedException {
ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 9999);
channelFuture.addListener((ChannelFutureListener) future -> {
if (!future.isSuccess()) {
final EventLoop loop = channelFuture.channel().eventLoop();
loop.schedule(() -> {
log.error("我与服务端失去了连接,我正在进行重连...");
try {
connect();
failedCount++;
} catch (InterruptedException e) {
e.printStackTrace();
}
}, 3L, TimeUnit.SECONDS);
} else {
System.err.println("服务端连接成功...");
}
});
//给关闭通道进行监听
channelFuture.channel().closeFuture().sync();
}
}
@Slf4j
class NettyClientHandler extends ChannelInboundHandlerAdapter {
private NettyClient nettyClient;
public NettyClientHandler(NettyClient nettyClient) {
this.nettyClient = nettyClient;
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
try {
ctx.pipeline().remove(this);
ctx.channel().close();
nettyClient.connect();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void channelActive(ChannelHandlerContext ctx) {
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
ByteBuf byteBuf = (ByteBuf) msg;
log.info("收到服务端消息:{}", byteBuf.toString(CharsetUtil.UTF_8));
}
}
3. 解答
-
NettyClientHandler的channelInactive感知到TCP连接的断开
-
NettyClient实例作为入参传递到Handler
-
如何杀掉一个TCP连接
-
测试步骤,客户端和服务端建立连接以后,把服务器断掉就会激活客户端的channelInactive, 然后再把服务器启动起来(我自己没杀成功)