简介

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

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

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