2021SC@SDUSC
上次先是搞清楚了ChannelFuture是什么,明白了ChannelFuture是用来支持异步回调事件,并且在代码中使用的是监听器做异步回调处理。
public void connect() throws Exception {
System.out.println("netty client start。。");
//启动客户端去连接服务器端
ChannelFuture cf = bootstrap.connect(host, port);
cf.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (!future.isSuccess()) {
//重连交给后端线程执行
future.channel().eventLoop().schedule(() -> {
System.err.println("重连服务端...");
try {
connect();
} catch (Exception e) {
e.printStackTrace();
}
}, 3000, TimeUnit.MILLISECONDS);
} else {
System.out.println("服务端连接成功...");
}
}
});
//对通道关闭进行监听
cf.channel().closeFuture().sync();
}
除了首次启动Client以外,重连时也再次使用到connect,具体的连接方法则是通过 future.channel().eventLoop().schedule()添加一个定时任务,不断重连直到成功,而这里就用到上次说过的
/**
* 将指定的侦听器添加到此Future。完成此操作时,将通知指定的侦听器。如果此Future已完成,则会立即通知指定的侦听器。
*/
Future<V> addListener(GenericFutureListener<? extends Future<? super V>> listener);
/**
* 当且仅当I/O操作成功完成时返回true。
*/
boolean isSuccess();
可以看到定时任务不断执行connect直到连接成功,同时也不会再添加定时任务。这就是能够在断线时客户端用来重连的方法。
解决了这个问题之后还有个需要解决的地方,那就是客户端怎么发现“失联”,如果客户端发现断线,那么只要重连就可以了。这里涉及的方法是hander里的
// channel 处于不活动状态时调用
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.err.println("运行中断开重连。。。");
nettyClient.connect();
}
channelInactive方法能在断开时自动启用,由于示例中使用的是客户端的重连,这里的channelInactive就是指服务器关闭,同样的服务器里也可以通过重写channelInactive实现重连,但示例中只是调用父类方法,在客户端关闭后删除客户端。
除此之外exceptionCaught也可以实现断线重连。因为exceptionCaught会在发生异常时被调用
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
System.err.println("运行中断开重连。。。");
nettyClient.connect();
}
需要注意的是如果同时实现了channelInactive和exceptionCaught则会同时重连两次。以下是过程
首先正常开启服务端和客户端,两者正常对话
此时断开服务器,大约每三秒重连
再次打开服务器还能再连上,如果一开始只打开客户端不打开服务器也是这个情况