netty客户端实现断线重连

388 阅读1分钟

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. 解答

  1. NettyClientHandler的channelInactive感知到TCP连接的断开

  2. NettyClient实例作为入参传递到Handler

  3. 如何杀掉一个TCP连接

  4. 测试步骤,客户端和服务端建立连接以后,把服务器断掉就会激活客户端的channelInactive, 然后再把服务器启动起来(我自己没杀成功)