断线重接更好用的 *** netty断线重连原理( 三 )


效劳器端遏制台输入的日记
不妨看到,存户端在发送4个心跳包后,第5个包由于等候功夫较长,比及真实发送的功夫,创造贯穿已割断了;而效劳器端收到存户端的4个心跳数据包后,迟迟等不到下一个数据包,以是顽强割断该贯穿 。
特殊情景
在尝试进程中,有大概会展示如次情景:
特殊情景
展示这种情景的因为是:在贯穿已割断的情景下,仍旧向效劳器端发送心跳包 。固然在发送心跳包之前会运用channel.isActive()确定贯穿能否可用,但也有大概上一刻确定截止为可用,但下一刻发送数据包之前,贯穿就断了 。
暂时尚未找到优美处置这种情景的计划,诸位看官即使有好的处置计划,还望不惜指教 。拜谢!!!
断线重连
断线重连这边就然而多引见,断定诸位都领会是如何回事 。这边只说大概思绪,而后径直上代码 。
实行思绪
存户端在监测到与效劳器端的贯穿割断后,大概一发端就没辙贯穿的情景下,运用指定的重连战略举行重连操纵,直到从新创造贯穿或重试度数耗尽 。
对于怎样监测贯穿能否割断,则是经过重写ChannelInboundHandler#channelInactive来实行,但贯穿不行用,该本领会被触发,以是只须要在该本领做好重连处事即可 。
代码实行
注:以次代码都是在上头心跳体制的普通上窜改/增添的 。
由于断线重连是存户端的处事,以是只需对存户端代码举行窜改 。
重试战略
RetryPolicy —— 重试战略接口
public interface RetryPolicy { /** * Called when an operation has failed for some reason. This method should return * true to make another attempt. * * @param retryCount the number of times retried so far (0 the first time) * @return true/false */ boolean allowRetry(int retryCount); /** * get sleep time in ms of current retry count. * * @param retryCount current retry count * @return the time to sleep */ long getSleepTimeMs(int retryCount);}ExponentialBackOffRetry —— 重连战略的默许实行
/** * <p>Retry policy that retries a set number of times with increasing sleep time between retries</p> */public class ExponentialBackOffRetry implements RetryPolicy { private static final int MAX_RETRIES_LIMIT = 29; private static final int DEFAULT_MAX_SLEEP_MS = Integer.MAX_VALUE; private final Random random = new Random(); private final long baseSleepTimeMs; private final int maxRetries; private final int maxSleepMs; public ExponentialBackOffRetry(int baseSleepTimeMs, int maxRetries) { this(baseSleepTimeMs, maxRetries, DEFAULT_MAX_SLEEP_MS); } public ExponentialBackOffRetry(int baseSleepTimeMs, int maxRetries, int maxSleepMs) { this.maxRetries = maxRetries; this.baseSleepTimeMs = baseSleepTimeMs; this.maxSleepMs = maxSleepMs; } @Override public boolean allowRetry(int retryCount) { if (retryCount < maxRetries) { return true; } return false; } @Override public long getSleepTimeMs(int retryCount) { if (retryCount < 0) { throw new IllegalArgumentException("retries count must greater than 0."); } if (retryCount > MAX_RETRIES_LIMIT) { System.out.println(String.format("maxRetries too large (%d). Pinning to %d", maxRetries, MAX_RETRIES_LIMIT)); retryCount = MAX_RETRIES_LIMIT; } long sleepMs = baseSleepTimeMs * Math.max(1, random.nextInt(1 << retryCount)); if (sleepMs > maxSleepMs) { System.out.println(String.format("Sleep extension too large (%d). Pinning to %d", sleepMs, maxSleepMs)); sleepMs = maxSleepMs; } return sleepMs; }}ReconnectHandler—— 重连处置器
@ChannelHandler.Sharablepublic class ReconnectHandler extends ChannelInboundHandlerAdapter { private int retries = 0; private RetryPolicy retryPolicy; private TcpClient tcpClient; public ReconnectHandler(TcpClient tcpClient) { this.tcpClient = tcpClient; } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { System.out.println("Successfully established a connection to the server."); retries = 0; ctx.fireChannelActive(); } @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { if (retries == 0) { System.err.println("Lost the TCP connection with the server."); ctx.close(); } boolean allowRetry = getRetryPolicy().allowRetry(retries); if (allowRetry) { long sleepTimeMs = getRetryPolicy().getSleepTimeMs(retries); System.out.println(String.format("Try to reconnect to the server after %dms. Retry count: %d.", sleepTimeMs, ++retries)); final EventLoop eventLoop = ctx.channel().eventLoop(); eventLoop.schedule(() -> { System.out.println("Reconnecting ..."); tcpClient.connect(); }, sleepTimeMs, TimeUnit.MILLISECONDS); } ctx.fireChannelInactive(); } private RetryPolicy getRetryPolicy() { if (this.retryPolicy == null) { this.retryPolicy = tcpClient.getRetryPolicy(); } return this.retryPolicy; }}ClientHandlersInitializer
在之前的普通上,增添了重连处置器ReconnectHandler 。

推荐阅读