Nett中的心跳機制與斷線重連詳解
心跳機制
我們以客戶端發(fā)送心跳為例,平時我們的心跳實現(xiàn)方式可能是搞個定時器,定時發(fā)送是吧,但是在Netty中卻不一樣,心跳被稱為空閑檢測,因為心跳的最主要作用就是判斷是否存活、是否假死等情況,所以Netty中并不是定時發(fā)送,而是空閑的情況下才發(fā)送,空閑指的是一段時間內無讀寫事件的發(fā)生,也就是沒有信息接收和信息發(fā)送啦,這時候我就要檢測一下了
所以Netty的機制就是通過監(jiān)測一段時間內是否有信息的讀、寫發(fā)生,然后產(chǎn)生一個事件,我們可以處理這個事件來達到我們的目的
IdleStateHandler
心跳與其他的數(shù)據(jù)處理Handler一樣,都是建立連接后的數(shù)據(jù)處理,所以同樣都是處理管道中的,IdleStateHandler就是Netty幫我們封裝好了的處理類,我們可以直接使用并將它放入管道中,就可以自動檢測一段時間內是否有讀、寫發(fā)生了,常用的構造有4個參數(shù):
- readerIdleTime:讀事件檢測,該時間內沒有信息讀取就會產(chǎn)生一個讀信息的事件
- writerIdleTime:寫事件檢測,該時間內沒有信息發(fā)送就會產(chǎn)生一個寫信息的事件
- allIdleTime:讀寫事件檢測,該時間內沒有信息發(fā)送或者讀取就會產(chǎn)生一個讀寫信息的事件
- unit:時間單位
public IdleStateHandler(long readerIdleTime, long writerIdleTime, long allIdleTime, TimeUnit unit) { this(false, readerIdleTime, writerIdleTime, allIdleTime, unit); }
使用:
// 管道中直接添加 // 時間配置為0則代表不檢測對應事件 channel.pipeline().addLast(new IdleStateHandler(5,0,0, TimeUnit.SECONDS))
觸發(fā)的事件類型:
- IdleState.READER_IDLE:讀信息的事件
- IdleState.WRITER_IDLE:寫信息的事件
- IdleState.ALL_IDLE:讀寫信息的事件
舉個例子:假設我們是客戶端主動發(fā)送心跳,那客戶端就要檢測一段時間內是否有寫信息的操作,如果沒有就會觸發(fā)IdleState.WRITER_IDLE事件,那我們監(jiān)聽這個事件,就做出自己的處理,那就是主動發(fā)送心跳包嘛
下面我們就以客戶端發(fā)送心跳包為例!
客戶端
像上面那樣直接使用IdleStateHandler,那還需要單獨寫一個事件處理的類,所以這里我們直接繼承IdleStateHandler
ClientHeartbeatHandler 如下:
我們設置5秒,5秒內沒有寫過信息,我們就發(fā)送心跳包(這里消息很隨意,圖方便)
@Slf4j public class ClientHeartbeatHandler extends IdleStateHandler { // 設置寫事件為5s // 如果5s沒有寫事件發(fā)生 就會觸發(fā)下面的IdleStateEvent private static final int WRITE_IDLE_TIME = 5; public ClientHeartbeatHandler() { super(0, WRITE_IDLE_TIME, 0, TimeUnit.SECONDS); } @Override protected void channelIdle(ChannelHandlerContext ctx, IdleStateEvent evt) throws Exception { // 指定時間內沒有寫事件發(fā)送 就會觸發(fā) IdleState.WRITER_IDLE 類型事件 // 我們就可以對該連接進行處理 主動發(fā)送心跳 if(evt.state()== IdleState.WRITER_IDLE){ log.info("{} 秒內沒有發(fā)送數(shù)據(jù),再不發(fā)送小心和服務端斷開連接", WRITE_IDLE_TIME); ctx.writeAndFlush(new NettyMsg(ServiceCodeEnum.TEST_TYPE,"我還活著,不要斷開連接")); } } }
NettyClient
管道中加入這個即可,注意要放在編解碼之后
服務端
基本跟客戶端一樣,但是由于是客戶端給我發(fā)心跳,所以服務端要監(jiān)測讀事件
ServerHeartbeatHandler
這里我們設置10s,一般會更多因為要給客戶端一些容忍度,適量就好,一旦沒滿足就和客戶端斷開連接
@Slf4j public class ServerHeartbeatHandler extends IdleStateHandler { // 設置讀取事件為10s // 如果10s沒有讀事件發(fā)生 就會觸發(fā)下面的IdleStateEvent private static final int READER_IDLE_TIME = 10; public ServerHeartbeatHandler() { super(READER_IDLE_TIME, 0, 0, TimeUnit.SECONDS); } @Override protected void channelIdle(ChannelHandlerContext ctx, IdleStateEvent evt) throws Exception { // 指定時間內沒有讀事件發(fā)送 就會觸發(fā) IdleState.READER_IDLE 類型事件 // 我們就可以對該連接進行處理 這里是直接關閉 if(evt.state()== IdleState.READER_IDLE){ log.info("{} 秒內沒有讀取到數(shù)據(jù),關閉連接", READER_IDLE_TIME); ctx.channel().close(); } } }
NettyServer
測試
正常情況
服務端
客戶端
異常情況
我們將客戶端心跳拉長
可以發(fā)現(xiàn)時間一到自動斷連
總結
這里是以客戶端發(fā)送心跳為例,如果是以服務端發(fā)送心跳也是一樣,主要就是對讀寫事件的監(jiān)聽,然后做出相應處理,上面其實是很隨意的哈,正常情況下心跳包是會用專門的消息類型的,而且服務端也需要做出應答的,心跳應答也會有對應的消息類型
斷線重連
這個就很簡單了,肯定是斷線后,客戶端發(fā)起重連嘛,就是在客戶端檢測到連接斷開的時候,重新連接就好了
ClientHeartbeatHandler加上一段:
看看效果,客戶端心跳時間還是12s哈
能這么隨意嗎?當然不行啊,別學我,正常會搞多次重連,而且謹慎起見,每次重連還可以加一個時間的間隔,可以學一下nacos里面的高級玩法,隨著重連次數(shù)的增加,間隔重試的時間也隨之增加,比如:
第一次重連是4s,第二次重連是8s,第三次是16s,以此類推
也就是設置重連間隔時間基數(shù)為4s,每嘗試一次,左移一位(4<<1),連接成功后基數(shù)復位為4s
需要設置最大重試次數(shù),最長間隔時間(一直左移后面會很長時間,所以要設置一個上限,超過了就以上限為準)
偽代碼如下:
@Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { log.info(ctx.channel().remoteAddress() + " 已斷開連接,開始重連"); int maxRetryNum=6; //最大重連次數(shù) int maxRetryTime=60; // 最大重連時間 int baseRetryTime=4; // 間隔時間基數(shù) // 開始重連 for (int i = 1; i <= maxRetryNum; i++) { log.info("第{}次重連,間隔{}s后開始",i,baseRetryTime > maxRetryTime ? maxRetryTime:baseRetryTime); ctx.channel().eventLoop().schedule(()->{ // 重連操作 // ....... // 判斷是否超過隔間上限 },baseRetryTime > maxRetryTime ? maxRetryTime:baseRetryTime,TimeUnit.SECONDS); // 左移擴大一倍 baseRetryTime = baseRetryTime << 1; } log.info("這么多次重連都不行寄了吧"); }
偽代碼哈,偽代碼!
結果如下:
建立連接后,手動關閉服務端,可以看到重連了6次,每次間隔時間翻倍,達到間隔時間上限后,就以上限的時間為準
到此這篇關于Nett中的心跳機制與斷線重連詳解的文章就介紹到這了,更多相關Nett心跳機制內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Java 在PPT中創(chuàng)建散點圖的實現(xiàn)示例
本文將以Java代碼示例展示如何在PPT幻燈片中創(chuàng)建散點圖表。文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-11-11