简介
咱们在应用客户端和服务器端连贯的过程中,可能会因为各种问题导致客户端和服务器的连贯产生中断,遇到这种状况,个别状况下咱们须要应用监控程序去监听客户端和服务器端的连贯,如果第一工夫发现连贯断开了,就须要手动去重连。比拟麻烦,明天给大家介绍一种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/
最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!
欢送关注我的公众号:「程序那些事」,懂技术,更懂你!