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则会同时重连两次。以下是过程
首先正常开启服务端和客户端,两者正常对话
此时断开服务器,大约每三秒重连
再次打开服务器还能再连上,如果一开始只打开客户端不打开服务器也是这个情况