关于netty:netty系列之自动重连

37次阅读

共计 2883 个字符,预计需要花费 8 分钟才能阅读完成。

简介

咱们在应用客户端和服务器端连贯的过程中,可能会因为各种问题导致客户端和服务器的连贯产生中断,遇到这种状况,个别状况下咱们须要应用监控程序去监听客户端和服务器端的连贯,如果第一工夫发现连贯断开了,就须要手动去重连。比拟麻烦,明天给大家介绍一种 netty 中主动重连的形式。

应用 netty 建设连贯

要应用 netty 建设连贯,首先须要启动服务器,通常来说服务器通过应用 ServerBootstrap 来启动服务器,如下所示:

// 绑定端口并启动
ChannelFuture f = b.bind(PORT).sync();

对于客户端来说,能够通过 Bootstrap 按如下的形式启动:

// 连贯服务器
ChannelFuture f = b.connect(HOST, PORT).sync();

主动重连贯的原理

那么当客户端和服务器端的连贯断了之后,如何主动重连呢?

对于客户端来说,主动重连只须要再次调用 Bootstrap 的 connect 办法即可。当初的关键问题在于,如何找到从新调用 connect 的机会。

咱们晓得,不管 server 还是 client,对于音讯的解决都须要注册专门解决音讯的 handler。

对于读取音讯来说,个别须要继承 ChannelInboundHandlerAdapter,在这个 handler 中定义了很多和 channel 生命周期无关的办法,咱们能够从这些生命周期的办法动手。

一般来说客户端和服务器连贯的状态是这的:

CHANNEL REGISTERED–》CHANNEL ACTIVE –》READ –》READ COMPLETE –》CHANNEL INACTIVE –》CHANNEL UNREGISTERED

客户端和服务器端的连贯如果敞开的话,则会触发 CHANNEL INACTIVE 和 CHANNEL UNREGISTERED 两个事件,这样咱们在客户端重写上面两个办法,在办法中退出重连的逻辑即可。

    @Override
    public void channelInactive(final ChannelHandlerContext ctx) {println("连贯断开:" + ctx.channel().remoteAddress());
    }

    @Override
    public void channelUnregistered(final ChannelHandlerContext ctx) throws Exception {println("sleep:" + ReconnectClient.RECONNECT_DELAY + 's');

        ctx.channel().eventLoop().schedule(() -> {println("重连贯:" + ReconnectClient.HOST + ':' + ReconnectClient.PORT);
            ReconnectClient.connect();}, ReconnectClient.RECONNECT_DELAY, TimeUnit.SECONDS);
    }

在 channelInactive 办法中,咱们只是打印了一些日志。次要逻辑在 channelUnregistered 办法中,在这个办法中咱们首先通过 ctx 获取到以后的 channel,而后拿到 channel 中的 eventLoop,而后调用它的 schedule 办法,在给定的工夫后从新调用 connect() 办法。

connect() 办法返回的是一个 ChannelFuture,所以能够在 ChannelFuture 中增加一些 listener 用来监听 connect 的执行状态。

这里定义的 connect 办法如下:

    static void connect() {bs.connect().addListener(future -> {if (future.cause() != null) {
                handler.startTime = -1;
                handler.println("建设连贯失败:" + future.cause());
            }
        });
    }

模仿主动重连

上一节咱们曾经晓得怎么主动重连了,本大节将会对主动重连进行一个模仿。

这里要介绍一个类,叫做 IdleStateHandler,从名字就可以看进去这个类是当 Channel 没有做任何 read, write 操作的时候,就会触发这个 Idle 的状态。

示意 Idle 状态的类叫做 IdleStateEvent,Idle 有 6 个状态,别离是 FIRST_READER_IDLE_STATE_EVENT,READER_IDLE_STATE_EVENT,FIRST_WRITER_IDLE_STATE_EVENT,WRITER_IDLE_STATE_EVENT,FIRST_ALL_IDLE_STATE_EVENT 和 ALL_IDLE_STATE_EVENT。

别离示意读取状态的 IDLE,写状态的 IDLE 和读写状态的 IDLE。

这样咱们在 client 启动的时候就能够加上 IdleStateHandler,当 client 一段时间没有读取到 server 端发来的音讯的时候,咱们就调用 ctx.close() 将 channel 敞开,从而登程 client 端的重连操作。

        bs.group(group)
                .channel(NioSocketChannel.class)
                .remoteAddress(HOST, PORT)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {ch.pipeline().addLast(new IdleStateHandler(READ_TIMEOUT, 0, 0), handler);
                    }
                });

IdleStateEvent 是一个用户登程的 event,要捕捉到这个 event,须要重写 userEventTriggered:

    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {if (!(evt instanceof IdleStateEvent)) {return;}
        IdleStateEvent e = (IdleStateEvent) evt;
        if (e.state() == IdleState.READER_IDLE) {
            // 在 Idle 状态
            println("Idle 状态,敞开连贯");
            ctx.close();}
    }

下面的例子中,咱们捕捉了 IdleStateEvent,并判断如果 IdleState 的状态是 IdleState.READER_IDLE,那么就将 channel 敞开。

总结

本文咱们介绍了重连的原理和用户触发的 Event,心愿大家可能喜爱。

本文的例子能够参考:learn-netty4

本文已收录于 http://www.flydean.com/09-netty-reconnect/

最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!

欢送关注我的公众号:「程序那些事」, 懂技术,更懂你!

正文完
 0