斷線重接更好用的 *** 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 。

推薦閱讀