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