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