高效維持網路長連線:手把手教你實現 自適應的心跳保活機制
前言
- 當實現具備實時性需求時,我們一般會選擇長連線的通訊方式
- 而在實現長連線方式時,存在很多效能問題,如 長連線保活
- 今天,我將 手把手教大家實現自適應的心跳保活機制,從而能高效維持長連線
目錄
示意圖
1. 長連線 介紹
1.1 簡介
示意圖
1.2 作用
通過 長時間保持雙方連線,從而:
- 提高通訊速度
- 確保實時性
- 避免短時間內重複連線所造成的通道資源 & 網路資源的浪費
1.3 長連線 與 短連線的區別
示意圖
2. 長連線斷開的原因
-
從上節可知,在長連線的情況下,雙方的所有通訊 都建立在1條長連線上(1次
TCP
連線);所以,長連線 需要 持續保持雙方連線 才可使得雙方持續通訊 -
可是,長連線會存在斷開的情況,而 斷開原因 主要是:
- 長連線所在程式被殺死
NAT
超時- 網路狀態發生變化
- 其他不可抗因素(網路狀態差、
DHCP
的租期等等 )
下面,我將對每種原因進行分析
原因1:程式被殺死
當程式被殺死後,長連線也會隨之斷開
原因2:NAT 超時(重點關注)
- NAT超時現象如下
示意圖
- 各運營商 & 地區的 NAT超時時間如下
示意圖
- 特別注意:排除其他外因(網路切換、
NAT
超時、人為原因),TCP
長連線在雙方都不斷開連線的情況上,本質上是不會自動中斷的
- 即,不需要心跳包來維持
- 驗證:讓2臺電腦連上同1個
Wifi
(其中1臺做伺服器, 另1臺做客戶端連線伺服器(無設定KeepAlive
);只要電腦、路由器不斷網斷電,那麼,2臺電腦的長連線是不會自動中斷的。
原因3:網路狀態發生變化
當移動客戶端網路狀態發生變化時(如行動網路 & Wifi切換、斷開、重連),也會使長連線斷開
原因4:其他不可抗因素
如網路狀態差、DHCP
的租期到期等等,都會使得長連線發生 偶然的斷開
DHCP
的租期到期:對於Android
系統,DHCP
到了租期後不會主動續約 & 繼續使用過期IP,,從而導致長連線 斷開
3. 高效維持長連線的解決方案
- 在瞭解長連線斷開原因後,針對對應原因,此處給出 高效維持長連線的解決方案
示意圖
- 為此,若需有效維持長連線,則需要做到
示意圖
其實,說得簡單點:高效維持長連線的關鍵在於
- 保活:處於連線狀態時儘量不要斷
- 斷線重連:斷了之後繼續重連回來
解決方案1:程式保活
整體概括如下:
示意圖
解決方案2:心跳保活機制
這是本文的重點,下節開始會詳細解析
解決方案3:斷線重連機制
- 原理
檢測網路狀態變化 & 判斷連線的有效性 - 具體實現
前者請參考文章:Android:檢測網路狀態&監聽網路變化;後者主要存在於心跳保活機制,所以下面會在心跳保活機制中一起講解。
4. 心跳保活機制簡介
- 心跳保活機制的整體介紹如下
示意圖
- 注:很多人容易混淆 心跳機制 & 輪詢機制,此處給出二者區別
示意圖
5. 主流心跳機制分析 & 對比
對國、內外主流的移動IM
產品(WhatsApp
、Line
、微信)進行了心跳機制的簡單分析 & 對比,具體請看下圖
示意圖
6. 心跳機制方案 總體設計
下面,將根據市面上主流的心跳機制,設計 一套心跳機制方案
6.1 基本流程
示意圖
6.2 設計要點
- 對於心跳機制方案設計的主要考慮因素 = 保證訊息的實時性 & 耗費裝置的資源(網路流量、電量、CPU等等)
- 從上圖可以看出,對於心跳機制方案設計的要點在於
- 心跳包的規格(內容 & 大小)
- 心跳傳送的間隔時間
- 斷線重連機制 (核心 = 如何 判斷長連線的有效性)
在下面的方案設計中,將針對這3個問題給出詳細的解決方案。
7. 心跳機制方案 詳細設計
7.1 心跳包的規格
為了減少流量 & 提高傳送效率,需要精簡心跳包的設計
7.1.1 設計原則
主要從心跳包的內容 & 大小入手,設計原則具體如下
示意圖
7.1.2 設計方案
心跳包 = 1個攜帶少量資訊 & 大小在10位元組內的資訊包
7.2 心跳傳送的間隔時間
為了 防止NAT
超時 & 減少裝置資源的消耗(網路流量、電量、CPU等等),心跳傳送的間隔時間 是 整個 心跳機制方案設計的重點。
7.2.1 設計原則
心跳傳送間隔時間的設計原則如下
示意圖
7.2.2 設計方案
a. 最直接 & 常用方案
-
一般,最直接 & 常用的心跳傳送間隔時間設定方案 :每隔估計
x
分鐘傳送心跳包1次 -
即 選擇 <所有
NAT
超時時間最短(5分鐘)的時間 即可,綜合主流移動IM產品,此處建議 x= 4分鐘 -
但是,這種方案存在一些問題:
示意圖
下面,我將詳細講解 自適應心跳間隔時間 的設計方案
b. 自適應心跳間隔時間 設計方案
- 基本流程
示意圖
- 該方案需要解決的有2個核心問題:
1.如何自適應計算心跳間隔 從而使得心跳間隔 接近 當前NAT
超時時間?
答:不斷增加心跳間隔時間進行心跳應答測試,直到心跳失敗5次後,即可找出最接近 當前
NAT
超時時間的心跳間隔時間。具體請看下圖:
示意圖
注:只有當心跳間隔 接近 NAT
超時時間 時,才能最大化平衡 長連線不中斷 & 裝置資源消耗最低的問題。
2.如何檢測 當前網路環境的NAT
超時時間 發生了變化 ?
答:當前傳送心跳包成功 的最大間隔時間(即最接近NAT超時時間的心跳間隔) 傳送失敗5次後,則判斷當前網路環境的
NAT
超時時間 發生了變化。具體請看下圖:
示意圖
注:在檢測到 NAT
超時時間 發生變化後,重新自適應計算心跳間隔 從而使得心跳間隔 接近 NAT
超時時間
- 總結:統籌2個核心問題,總結出自適應心跳間隔時間 設計方案為下圖
示意圖
7.3 斷線重連機制
該機制的核心在於, 如何 判斷長連線的有效性
即,什麼情況下視為 長連線 斷線?
7.3.1 設計原則
- 判斷長連線是否有效的準則 = 伺服器是否返回心跳應答
- 此處需要 分清:長連線 存活 & 有效 狀態的區別:
示意圖
7.3.2 設計方案
- 基本思路
若連續5次傳送心跳後,伺服器都無心跳應答,則視為長連線無效
通過計數計算
- 判斷流程
示意圖
7.3.3 網上流傳的方案
在網上流傳著一些用於判斷長連線是否有效的方案,具體介紹如下
示意圖
至此,關於心跳保活機制已經講解完畢。
7.4 總結
- 設計方案
示意圖
- 流程設計
其中,標識 “灰色” 的判斷流程參考上文描述
示意圖
8. 優化 & 完善
- 上面的方案依然會存在缺陷,從而導致 長連線斷開
如,長連線本身不可用(此時重連多少次也沒用)
-
下面,將優化 & 完善上述方案,從而保證 客戶端與伺服器依然保持著通訊狀態
-
優化點
- 確保當前網路的有效性 & 穩定性再開始長連線
- 自適應計算心跳包間隔時間的時機
8.1 確保當前網路的有效性 & 穩定性再開始長連線
- 問題描述
示意圖
- 解決方案
示意圖
-
加入到原有 心跳保活機制 主流程
示意圖
8.2 自適應計算心跳包間隔時間的時機
- 問題描述
示意圖
- 方案設計
示意圖
- 加入到原有 心跳保活機制 主流程
示意圖
8.3 總結
示意圖
9. 額外說明:TCP 協議自帶 KeepAlive 的機制 是否 可替代心跳機制
很多人認為,TCP
協議自身就有KeepAlive
機制,為何基於它的通訊連結,仍需 在應用層實現額外的心跳保活機制?
9.1 回答
- 結論:無法替代
- 原因:
TCP KeepAlive
機制 的作用 是檢測連線的有無(死活),但無法檢測連線是否有效。
“連線有效”的定義 = 雙方具備傳送 & 接收訊息的能力
9.2 KeepAlive 機制概述
先來看看KeepAlive
機制 是什麼
示意圖
9.3 具體原因
KeepAlive
的機制 不可 替代心跳機制 的具體原因如下:
示意圖
9.4 特別注意
KeepAlive
機制只是作業系統底層的一個被動機制,不應該被上層應用層使用- 當系統關閉一個由
KeepAlive
機制檢查出來的死連線時,是不會主動通知上層應用的,只能通過呼叫相應IO
操作的返回值中發現
9.6 結論
KeepAlive
機制無法代替心跳機制,需要在應用層 自己實現心跳機制以檢測長連線的有效性,從而高效維持長連線
10. 實現方式
- 關於該心跳保活機制的實現方案,可採用多種方案實現
- 在
Android
端,本人推薦使用Rxjava
,因為:基於事件流的鏈式呼叫 的使用方式 使得 複雜方案 實現得更加優雅、邏輯簡潔 & 使用簡單
RxJava
簡介如下
示意圖
- 關於
RxJava
的使用,請看我係列文章:手把手帶你玩轉RxJava
11. 總結
- 看完本文後,相信在高效維持長連線的需求下,你可以完美地解決了!(具體總結如下)
示意圖
- 下面我將繼續對
Android
中的其他程式碼規範進行深入講解 ,有興趣可以繼續關注Carson_Ho的安卓開發筆記
相關文章
- 高效 實現長連線保活:手把手教你實現 自適應的心跳保活機制
- 萬字長文:手把手教你實現一套高效的IM長連線自適應心跳保活機制
- Netty(一) SpringBoot 整合長連線心跳機制NettySpring Boot
- 聊聊心跳機制及netty心跳實現Netty
- 手把手教你寫 Socket 長連線
- 從零開始實現簡單 RPC 框架 9:網路通訊之心跳與重連機制RPC框架
- 長連線的心跳保持設計
- 長連線的心跳及重連設計
- 即時通訊技術文集(第12期):網路保活、心跳機制等文章彙總 [共23篇]
- JAVA之長連線、短連線和心跳包Java
- Netty 如何高效接收網路資料?一文聊透 ByteBuffer 動態自適應擴縮容機制Netty
- Docker網路,手把手教你如何實現容器網路相關知識Docker
- 理解WebSocket心跳及重連機制(五)Web
- 聊聊 TCP 長連線和心跳那些事TCP
- Ceph心跳機制
- [譯]使用 JavaScript 和網路資訊 API 實現自適應服務JavaScriptAPI
- Socket程式設計-長連線與短連線,心跳(keep-alive)程式設計Keep-Alive
- CSS 圖片固定長寬比實現高度自適應CSS
- textarea實現高度自適應的理解
- 帶自注意力機制的生成對抗網路,實現效果怎樣?
- 心跳檢測機制
- Android客戶端網路預連線優化機制探究Android客戶端優化
- 自適應注意力機制在Image Caption中的應用APT
- 菜鳥學網路之 —— 長連線和短連線
- uni-app中websocket的使用 斷開重連、心跳機制APPWeb
- 全連線神經網路的原理及Python實現神經網路Python
- 車聯網中 MQTT 心跳保活與遠端喚醒設計MQQT
- Android客戶端網路預連線最佳化機制探究Android客戶端
- Qt 自動連線機制訊號與槽QT
- CentOS自動開啟網路連線CentOS
- 手把手教你寫網路爬蟲(5):PhantomJS實戰爬蟲JS
- xxl-job心跳機制
- 手機網路連線效能API介面:查詢手機網路連線效能狀態API
- 效能優化 (十) APP 持續執行之程式保活實現優化APP
- Redis處理客戶端連線的內部實現機制RXRedis客戶端
- win10網路印表機怎麼連線 win10連線網路印表機的步驟Win10
- Android應用保活實踐Android
- 樂維網管平臺(三)如何高效管理無線網路