断线重接更好用的 *** 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,其余都是编解码器妥协决粘包,不妨忽视 。

推荐阅读