斷線重接更好用的 *** netty斷線重連原理

多條告白如次劇本只需引入一次
心跳體制
何為心跳
所謂心跳, 即在 TCP 長貫穿中, 存戶端和效勞器之間按期發送的一種特出的數據包, 報告對方本人還在線, 以保證 TCP 貫穿的靈驗性.
注:心跳包再有另一個效率,常常被忽視,即:一個貫穿即使長功夫不必,風火墻大概路由器就會割斷該貫穿 。
怎樣實行
中心Handler —— IdleStateHandler
在 Netty 中, 實行心跳體制的要害是 IdleStateHandler, 那么這個 Handler 怎樣運用呢? 先看下它的結構器:
public IdleStateHandler(int readerIdleTimeSeconds, int writerIdleTimeSeconds, int allIdleTimeSeconds) { this((long)readerIdleTimeSeconds, (long)writerIdleTimeSeconds, (long)allIdleTimeSeconds, TimeUnit.SECONDS);}這邊證明下三個參數的含意:
readerIdleTimeSeconds: 讀超時. 即當在指定的功夫間隙內沒有從 Channel 讀取到數據時, 會觸發一個 READER_IDLE 的 IdleStateEvent 事變.writerIdleTimeSeconds: 寫超時. 即當在指定的功夫間隙內沒罕見據寫入到 Channel 時, 會觸發一個 WRITER_IDLE 的 IdleStateEvent 事變.allIdleTimeSeconds: 讀/寫超時. 即當在指定的功夫間隙內沒有讀或寫操縱時, 會觸發一個ALL_IDLE 的 IdleStateEvent 事變.注:這三個參數默許的功夫單元是秒 。若須要指定其余功夫單元,不妨運用另一個結構本領:IdleStateHandler(boolean observeOutput, long readerIdleTime, long writerIdleTime, long allIdleTime, TimeUnit unit)
在看底下的實行之前,倡導先領會一下IdleStateHandler的實行道理 。
底下徑直上代碼,須要提防的場合,會在代碼中經過解釋舉行證明 。
運用IdleStateHandler實行心跳
底下將運用IdleStateHandler來實行心跳,Client端貫穿到Server端后,會輪回實行一個工作:隨機等候幾秒,而后ping一下Server端,即發送一個心跳包 。當等候的功夫勝過規則功夫,將會發送波折,覺得Server端在此之前仍舊積極割斷貫穿了 。代碼如次:
Client端
ClientIdleStateTrigger —— 心跳觸發器
類ClientIdleStateTrigger也是一個Handler,不過重寫了userEventTriggered本領,用來捕捉IdleState.WRITER_IDLE事變(未在指定功夫內向效勞器發送數據),而后向Server端發送一個心跳包 。
/** * <p> * 用來捕捉{@link IdleState#WRITER_IDLE}事變(未在指定功夫內向效勞器發送數據),而后向<code>Server</code>端發送一個心跳包 。* </p> */public class ClientIdleStateTrigger extends ChannelInboundHandlerAdapter { public static final String HEART_BEAT = "heart beat!"; @Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { if (evt instanceof IdleStateEvent) { IdleState state = ((IdleStateEvent) evt).state(); if (state == IdleState.WRITER_IDLE) { // write heartbeat to server ctx.writeAndFlush(HEART_BEAT); } } else { super.userEventTriggered(ctx, evt); } }}Pinger —— 心跳放射器
/** * <p>存戶端貫穿到效勞器端后,會輪回實行一個工作:隨機等候幾秒,而后ping一下Server端,即發送一個心跳包 。</p> */public class Pinger extends ChannelInboundHandlerAdapter { private Random random = new Random(); private int baseRandom = 8; private Channel channel; @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { super.channelActive(ctx); this.channel = ctx.channel(); ping(ctx.channel()); } private void ping(Channel channel) { int second = Math.max(1, random.nextInt(baseRandom)); System.out.println("next heart beat will send after " + second + "s."); ScheduledFuture<?> future = channel.eventLoop().schedule(new Runnable() { @Override public void run() { if (channel.isActive()) { System.out.println("sending heart beat to the server..."); channel.writeAndFlush(ClientIdleStateTrigger.HEART_BEAT); } else { System.err.println("The connection had broken, cancel the task that will send a heart beat."); channel.closeFuture(); throw new RuntimeException(); } } }, second, TimeUnit.SECONDS); future.addListener(new GenericFutureListener() { @Override public void operationComplete(Future future) throws Exception { if (future.isSuccess()) { ping(channel); } } }); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { // 當Channel仍舊割斷的情景下, 仍舊發送數據, 會拋特殊, 該本領會被挪用. cause.printStackTrace(); ctx.close(); }}ClientHandlersInitializer —— 存戶端處置器匯合的初始化類
public class ClientHandlersInitializer extends ChannelInitializer<SocketChannel> { private ReconnectHandler reconnectHandler; private EchoHandler echoHandler; public ClientHandlersInitializer(TcpClient tcpClient) { Assert.notNull(tcpClient, "TcpClient can not be null."); this.reconnectHandler = new ReconnectHandler(tcpClient); this.echoHandler = new EchoHandler(); } @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4)); pipeline.addLast(new LengthFieldPrepender(4)); pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8)); pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8)); pipeline.addLast(new Pinger()); }}注: 上頭的Handler匯合,除去Pinger,其余都是編解碼器妥協決粘包,不妨忽視 。

推薦閱讀