1. 程式人生 > >長連線及心跳保活原理簡介

長連線及心跳保活原理簡介

轉載地址:https://caofengbin.github.io/2018/03/16/dhcp-and-nat/

長連線及心跳保活原理簡介

  本文簡要的分析了長連線產生的背景以及所解決的問題,並對比了keep-alive與心跳機制對長連線保活的影響,最後詳細的介紹了心跳保活的兩個關鍵因素–DHCP協議與NAT原理。如有不當之處,歡迎批評和指正。


1.短連線,並行連線,持久連線與長連線

(1) 短連線簡介

  在網際網路發展過程中,最為普及的應用就是HTTP超文字傳輸協議,而在早期–HTTP1.0的協議都是建立在TCP協議基礎上,其特點就是傳輸完資料後,立馬就釋放掉該TCP連結

,所以就有了形象的短連線這個稱號。下圖形象的展示出了在一個事務的處理過程中,各個階段的處理時長:

image_1c8acepra1ko1m287rb1mi3qes9.png-38.9kB

  可以看到,與建立TCP連線,以及傳輸請求和響應報文的時間相比,事務處理時間可能是很短的。短連線的效能瓶頸主要集中在如下幾個方面:

a.TCP連線的握手時延

image_1c8acqp088hdctrpe113981ucrm.png-50.1kB

  在傳送資料之前,TCP要傳送兩個分組來建立連線(現代的TCP棧都允許客戶端在確認分組中傳送資料),此時,SYN/SYN+ACK握手會產生一個可測量的時延。

b.延遲確認

  每個TCP段都有一個序列號和資料完整性校驗和。每個段的接收者收到完好的段時,都會向傳送者回送小的確認分組。如果傳送者沒有在指定的視窗時間內收到確認資訊,傳送者就認為分組已被破壞或損毀,並重發資料。
  由於確認報文很小,所以TCP允許在發往相同方向的輸出資料分組中對其進行“捎帶”。TCP將返回的確認資訊與輸出的資料分組結合在一起,可以更有效地利用網路。為了增加確認報文找到同向傳輸資料分組的可能性,很多TCP棧都實現了一種“延遲確認”演算法。延遲確認演算法會在一個特定的視窗時間(通常是100~200毫秒)內將輸出確認存放在緩衝區中,以尋找能夠捎帶它的輸出資料分組。如果在那個時間段內沒有輸出資料分組,就將確認資訊放在單獨的分組中傳送。

c.TCP慢啟動

  TCP連線會隨著時間進行自我“調諧”,起初會限制連線的最大速度,如果資料成功傳輸,會隨著時間的推移提高傳輸的速度,這種調諧被稱為TCP慢啟動,用於防止因特網的突然過載和擁塞。
  由於存在這種擁塞控制特性,所以新連線的傳輸速度會比已經交換過一定量資料的、“已調諧”連線慢一些。

(2) 短連線的適用場景與優缺點

  短連線多用於操作頻繁,點對點的通訊,而且連線數不能太多的情況。每個TCP連線的建立都需要三次握手,每個TCP連線的斷開要四次揮手。適用於併發量大,但是每個使用者又不需頻繁操作的情況。
  但是在使用者需要頻繁操作的業務場景下(如新使用者註冊,網購提交訂單等),頻繁的使用短連線則會使效能時延產生疊加,如下如:

image_1c8adodlr1ad4cr91uu9unf1e3413.png-61.4kB

  因此就產生了一些列關於連線效能的改進方案。

(3) 並行連線

  並行連線允許客戶端開啟多條連線,並行地執行多個事務,每個事務都有自己的TCP連線。這樣可以克服單條連線的空載時間和頻寬限制,時延可以重疊起來,而且如果單條連線沒有充分利用客戶端的網路頻寬,可以將未用頻寬分配來裝載其他物件。
  在PC時代,利用並行連線來充分利用現代瀏覽器的多執行緒併發下載能力的場景非常廣泛。
  但是並行連線也會產生一定的問題,首先並行連線不一定更快,因為頻寬資源有限,每個連線都會去競爭這有限的頻寬,這樣帶來的效能提升就很小,甚至沒什麼提升。另外開啟大量連線會消耗很多記憶體資源,從而引發自身的效能問題,因此每個瀏覽器,允許對每個域名的連線數一般是有上限的,如下圖所示:

image_1c8aeqcro1gpnohp1j8ng18pd9.png-89kB

(4) 持久連線

  HTTP1.0版本以後,允許HTTP裝置在事務處理結束之後將TCP連線保持在開啟狀態,以便為未來的HTTP請求重用現存的連線。在事務處理結束之後仍然保持在開啟狀態的TCP連線被稱為持久連線。非持久連線會在每個事務結束之後關閉。持久連線會在不同事務之間保持開啟狀態,直到客戶端或伺服器決定將其關閉為止。
  現在很多方案都會採用持久連線+新連線結合的方式,這種方式儘可能的減少了新建連線的浪費,同時當現有連線沒有辦法滿足需求的時候,可以建立新連線滿足需求,比較靈活。
  持久連線的時間引數,通常由伺服器設定,比如nginx的keepalivetimeout,keepalive timout時間值意味著:一個http產生的tcp連線在傳送完最後一個響應後,還需要hold住keepalive_timeout秒後,才開始關閉這個連線;

  持久連線與並行連線相比,帶來的優勢如下:

  • 避免了每個事務都會開啟/關閉一條新的連線,造成時間和頻寬的耗費;
  • 避免了TCP慢啟動特性的存在導致的每條新連線的效能降低;
  • 可開啟的並行連線數量實際上是有限的,持久連線則可以減少建立的連線的數量;

(5) 長連線

  長連線與持久連線本質上非常的相似,持久連線側重於HTTP應用層,特指一次請求結束之後,伺服器會在自己設定的keepalivetimeout時間到期後才關閉已經建立的連線。長連線則是client方與server方先建立連線,連線建立後不斷開,然後再進行報文傳送和接收,直到有一方主動關閉連線為止。

  長連線的適用場景也非常的廣泛:

  • 監控系統:後臺硬體熱插拔、LED、溫度、電壓發生變化等;
  • IM應用:收發訊息的操作;
  • 即時報價系統:例如股市行情push等;
  • 推送服務:各種App內建的push提醒服務;

  像以上這些連線,如果每次操作都要建立連線然後再操作的話處理速度會降低,並且時效性也不高。通過長連線,第一次連線上以後每次直接傳送資料就可以了,不用再建立TCP連線。


2.長連線保活,Keep-Alive與心跳保活技術

(1) 為何需要長連線保活

  上一節的分析可以看到,對於客戶端而言,使用TCP長連線來實現業務的好處在於:在當前連線可用的情況下,每一次請求都只是簡單的資料傳送和接受,免去了DNS解析,連線建立,TCP慢啟動等時間,大大加快了請求的速度,同時也有利於接收伺服器的實時訊息。
  在使用TCP長連線的業務場景下,保持長連線的可用性非常重要。如果長連線無法很好地保持,在連線已經失效的情況下繼續傳送請求會導致遲遲收不到響應直到超時,又需要一次連線建立的過程,其效率甚至還不如直接使用短連線。而連線保持的前提必然是檢測連線的可用性,並在連線不可用時主動放棄當前連線並建立新的連線。

(2) 心跳保活

  App實現長連線保活的方式通常是採用應用層心跳,通過心跳包的超時和其他條件(網路切換)來執行重連操作。心跳一般是指某端(絕大多數情況下是客戶端)每隔一定時間向對端傳送自定義指令,以判斷雙方是否存活,因其按照一定間隔傳送,類似於心跳,故被稱為心跳指令。

(3) Keep-Alive可否實現保活?

a.HTTP中的Keep-Alive

  實現HTTP/1.0 keep-alive連線的客戶端可以通過包含Connection:Keep-Alive首部請求將一條連線保持在開啟狀態,如果伺服器願意為下一條請求將連線保持在開啟狀態,就在響應中包含相同的首部。如果響應中沒有Connection: Keep-Alive首部,客戶端就認為伺服器不支援keep-alive,會在發回響應報文之後關閉連線。HTTP/1.1以後Keep-Alive是預設開啟的。

c.TCP中的Keep-Alive

  TCP協議的實現中,提供了KeepAlive報文,用來探測連線的對端是否存活。在應用互動的過程中,可能存在以下幾種情況:

  • 客戶端或伺服器意外斷電,宕機,崩潰,重啟;
  • 中間網路已經中斷,而客戶端與伺服器並不知道;

  利用保活探測功能,可以探知這種對端的意外情況,從而保證在意外發生時,可以釋放半開啟的TCP連線。TCP保活報文互動過程如下:

image_1c8ai46ncp561qieot2n0h15p5m.png-174.7kB

  雖然TCP提供了KeepAlive機制,但是並不能替代應用層心跳保活。原因主要如下:

  • (1) Keep Alive機制開啟後,TCP層將在定時時間到後傳送相應的KeepAlive探針以確定連線可用性。預設時間為7200s(兩小時),失敗後重試10次,每次超時時間75s。顯然預設值無法滿足行動網路下的需求;
  • (2) 即便修改了(1)中的預設值,也不能很好的滿足業務需求。TCP的KeepAlive用於檢測連線的死活而不能檢測通訊雙方的存活狀態。比如某臺伺服器因為某些原因導致負載超高,無法響應任何業務請求,但是使用TCP探針則仍舊能夠確定連線狀態,這就是典型的連線活著但業務提供方已死的狀態,對客戶端而言,這時的最好選擇就是斷線後重新連線其他伺服器,而不是一直認為當前伺服器是可用狀態,一直向當前伺服器傳送些必然會失敗的請求。
  • (3) socks代理會讓Keep Alive失效。socks協議只管轉發TCP層具體的資料包,而不會轉發TCP協議內的實現細節的包。所以,一個應用如果使用了socks代理,那麼TCP的KeepAlive機制就失效了。
  • (4) 部分複雜情況下Keep Alive會失效,如路由器掛掉,網線直接被拔除等;

  因此,KeepAlive並不適用於檢測雙方存活的場景,這種場景還得依賴於應用層的心跳。應用層心跳也具備著更大的靈活性,可以控制檢測時機,間隔和處理流程,甚至可以在心跳包上附帶額外資訊。

(4) 影響心跳頻率的關鍵因素

  通過上一節的分析可以看到應用層心跳是檢測連線有效性以及判斷雙方是否存活的有效方式。但是心跳過於頻繁會帶來耗電和耗流量的弊病,心跳頻率過低則會影響連線檢測的實時性。業內關於心跳時間的設定和優化,主要基於如下幾個因素:

  • 1.NAT超時–大部分移動無線網路運營商在鏈路一段時間沒有資料通訊時,會淘汰 NAT表中的對應項,造成鏈路中斷;
  • 2.DHCP租期–DHCP租期到了需要主動續約,否則會繼續使用過期IP導致長連線偶然的斷連;
  • 3.網路狀態變化–手機網路和WIFI網路切換、網路斷開和連上等情況有網路狀態的變化,也會使長連線變為無效連線;

  網路狀態變化導致長連線變為無效連線的原因很容易理解。但是NAT超時和DHCP租期的問題對長連線保活存在的影響就涉及到網路協議底層的細節了。後續會對這兩個原理進行相應的分析。


3.DHCP原理淺析及其對心跳保活的影響

(1) DHCP協議簡介

  DHCP協議全稱為Dynamic Host Configuration Protocol– 動態主機配置協議,主要用於在一個局域網裡為主機動態的分配IP地址。DHCP有三種分配IP地址方式:

  • 自動分配:DHCP給客戶端分配永久性的IP地址;
  • 動態分配:DHCP給客戶端分配的IP地址過一段時間後會過期,或者客戶端可以主動釋放該地址(最常用的方式);
  • 手動配置:由使用者手動為客戶端指定IP地址;

(2) DHCP工作流程詳解

  DHCP協議為客戶端分配IP的過程大致如下:

DHCP分配IP的過程

1.DHCP Discover

  DHCP客戶端(需要上網的裝置)以廣播(因為客戶端還不知道DHCP伺服器的IP地址)的方式傳送DHCP Discover包,來尋找DHCP伺服器,即向地址255.255.255.255傳送特定的廣播資訊。網路上每一臺安裝了TCP/IP協議的主機都會收到該廣播訊息,但只有DHCP伺服器才會做出響應。

DHCPDiscover1.png-31.2kB

DHCPDiscover2.png-70kB

2.DHCP Offer

  在該階段,DHCP伺服器提供IP地址。在網路中接收到DHCP Discover包的DHCP伺服器,都會做出響應。這些DHCP伺服器從尚未出租的IP地址中挑選一個給客戶端,向客戶端傳送一個包含IP地址和其他設定的DHCP Offer包。

DHCPOffer1.png-36.6kB

DHCPOffer2.png-128.8kB

3.DHCP Request

DHCP確認.png-218.1kB
  該階段需要DHCP客戶端選擇某臺DHCP伺服器提供的IP地址,如上圖所示,可以看到3臺DHCP伺服器都向客戶端傳送了DHCP Offer,此時,DHCP客戶端只能接受第一個收到的DHCP Offer包資訊。然後,以廣播的方式回答一個DHCP Request請求資訊,該資訊中包含它所選定的DHCP伺服器請求IP地址的內容。

DHCPRequest.png-84.4kB

4.DHCP ACK

  確認階段,DHCP伺服器確認所提供的的IP地址階段,告訴DHCP客戶端可以使用它所提供的IP地址。

DHCP_ACK.png-88.7kB

(3) DHCP的續租問題

  在DHCP ACK報文中,有3個關於續租時間相關的欄位:

  • Lease Time:
    IP地址租約時間,超過了這個時間後,IP地址被DHCP伺服器收回;
  • Renewal Time:
    預設為Lease Time的1/2,表示客戶端需要進行續約的時間。客戶端傳送一個DHCP REQUEST訊息給原始的DHCP伺服器,並等待回覆。DHCP伺服器返回DHCP ACK則表示同意續期,客戶端更新自己的Renewal Time與Rebinding Time即可。
  • Rebinding Time:
    預設為Lease Time的7/8,客戶端在續期失敗的情況下,Rebinding Time到期時,會向區域網內廣播發送一條DHCP REQUEST訊息,如果還沒有DHCP伺服器響應直至租約Lease Time到期,將恢復到初始狀態。

  DHCP完成的狀態變遷流程如下:

DHCP狀態圖.PNG-156.6kB

(4) DHCP租期問題對心跳保活的影響

  在設計心跳頻率時,DHCP租期是一個不確定因素,但是原則是心跳的最大間隔應該低於DHCP的租期時間。
  另外,在Android的一些版本上,存在DHCP租期到了不會主動續約並且會繼續使用過期IP的bug。這個問題導致的問題表象是,在超過租期的某個時間點(沒有規律)會導致IP過期,老的TCP連線不能正常收發資料。並且系統沒有網路變化事件,只有等應用判斷主動建立新的TCP連線才引起安卓裝置重新向DHCP Server申請IP租用。詳情可見–Android 2.1 - 4.1.1 Allows DHCP Lease to Expire, Keeps Using IP Address。


4.NAT原理淺析及其對心跳保活的影響

(1) NAT技術產生的背景

  在網路協議制定的初期設計網路地址的時候,32bits位長即2的32次冪臺終端裝置連入網際網路已經是一個非常大的數量了,再加上增加ip的長度(即使是從4位元組增到6位元組)對當時裝置的計算、儲存、傳輸成本也是相當巨大的。因此IP地址設計為了32位,並且在早期所有需要上網的裝置都有自己的IP地址,也就是說那個時候沒有內網和外網的區別,所有客戶端都是直接連線到網際網路的
  進入20世紀90年代之後,網際網路逐步向公眾普及,接入網際網路的裝置數量也快速增長,如果還用原來的方法接入,過不了多久,可分配的地址就用光了。如果不能保證每臺裝置有唯一不重複的地址,就會從根本上影響網路包的傳輸,這是一個非常嚴重的問題。如果任由這樣發展下去,不久的將來,一旦固定地址用光,新的裝置就無法接入了。在這個背景下NAT技術誕生了(雖然ipv6也是解決辦法,但始終普及不開來,而且未來到底ipv6夠不夠用仍是未知)。

(2) NAT技術的基本工作原理

a.NAT技術的本質

  NAT技術主要是為了解決公網IP地址不足的問題,所以才會採取這種地址轉換的策略。本質上就是讓一群機器公用同一個IP,這樣就暫時解決了IP短缺的問題。

b.私有地址與公有地址

  不同內網之間是完全獨立的。內網之間不會有網路包流動,即使內網A的某臺伺服器和內網B的某臺客戶端具有相同的IP地址也沒關係,因為它們之間不會進行通訊。只要在每個內網自己的範圍內,能夠明確判斷網路包的目的地就可以了,是否和其他區域網中的內網地址重複無關緊要,只要每個區域網自己的網路是相互獨立的,
就不會出現問題。
  解決地址不足的問題,利用的就是這樣的原理,即區域網的內部裝置的地址不一定要和其他區域網中的內部裝置地址不重複。這樣一來,區域網的內部裝置就不需要分配固定地址了,從而大幅節省了IP地址。內部裝置分配IP地址的方式,就是通過上一節的DHCP協議進行。內網地址的分配有相應的規則,規定某些地址是用於內網的,這些地址叫作私有地址,而原來的固定地址則叫作公有地址。
  在內網中可用作私有地址的範圍僅限以下這些:

  • 10.0.0.0~10.255.255.255
  • 172.16.0.0~172.31.255.255
  • 192.168.0.0~192.168.255.255

  在制定私有地址規則時,這些地址屬於公有地址中還沒有分配的範圍。換句話說,私有地址本身並沒有什麼特別的結構,只不過是將公有地址中沒分配的一部分拿出來規定只能在內網使用它們而已。

c.地址轉換(NAT)機制的加入

  當內網和網際網路之間需要傳輸包的時候,問題就出現了,因為如果很多地方都出現相同的地址,包就無法正確傳輸了。因此當公司內網和網際網路連線的時候,需要採用下圖這樣的結構,即將公司內網分成兩個部分,一部分是對網際網路開放的伺服器,另一部分是公司內部裝置。其中對網際網路開放的部分分配公有地址,可以和網際網路直接進行通訊。相對地,內網部分則分配私有地址,內網中的裝置不能和網際網路直接收發網路包,而是通過一種特別的機制進行連線,這個機制就叫地址轉換。

公有地址和私有地址.png-70.6kB

d.地址轉換(NAT)的基本原理

  地址轉換的基本原理是在轉發網路包時對IP頭部中的IP地址和埠號進行改寫,如下圖所示:TCP連線操作的第一個包被轉發到網際網路時,會將傳送方IP地址從私有地址改寫成公有地址。這裡使用的公有地址是地址轉換裝置的網際網路接入埠的地址。與此同時,埠號也需要進行改寫,地址轉換裝置會隨機選擇一個空閒的埠。然後,改寫前的私有地址和埠號,以及改寫後的公有地址和埠號,會作為一組相對應的記錄儲存在地址轉換裝置內部的一張表(NAT表)中

地址轉換的基本原理.png-103kB

  改寫傳送方IP地址和埠號之後,包就被髮往網際網路,最終到達伺服器,然後伺服器會返回一個包。伺服器返回的包的接收包是原始包的傳送方,因此返回的包的接收方就是改寫後的公有地址和埠號。這個公有地址其實是地址轉換裝置的地址,因此這個返回包就會到達地址轉換裝置。接下來,地址轉換裝置會從地址對應表中通過公有地址和埠號找到相對應的私有地址和埠號,並改寫接收方資訊,然後將包發給區域網的內部裝置,這樣包就能夠到達原始的傳送方了。

e.為什麼需要改寫埠號?

  早期的地址轉換機制是隻改寫地址,不改寫埠號的。使用這種方法的前提是私有地址和公有地址必須一一對應,也就是說,有多少臺裝置需要同時訪問網際網路,就需要多少個公有地址。訪問動作結束後可以刪除對應表中的記錄,這時同一個公有地址可以分配給其他裝置使用。
  後續隨著網際網路的發展,同一個局域網裡的裝置也越來越多。改寫埠號正是為了解決這個問題。客戶端一方的埠號本來就是從空閒埠中隨機選擇的,因此改寫了也不會有問題。埠號是一個16位元的數值,總共可以分配出幾萬個埠,因此如果用公有地址加上埠的組合對應一個私有地址,一個公有地址就可以對應幾萬個私有地址,這種方法提高了公有地址的利用率。

(3) NAT技術帶來的弊端

  首先,NAT使IP會話的保持時效變短。因為NAT表中的每一條記錄,在會話靜默的這段時間,NAT閘道器會進行老化操作。這是任何一個NAT閘道器必須做的事情,因為IP和埠資源有限,通訊的需求無限,所以必須在會話結束後回收資源。通常TCP會話通過協商的方式主動關閉連線,NAT閘道器可以跟蹤這些報文,但總是存在例外的情況,要依賴自己的定時器(NAT超時機制)去回收資源。通過NAT超時機制回收會帶來一個問題,如果應用需要維持連線的時間大於NAT閘道器的設定,通訊就會意外中斷。因為網關回收相關轉換表資源以後,新的資料到達時就找不到相關的轉換資訊,必須建立新的連線。

  其次,NAT在實現上將多個內部主機發出的連線複用到一個IP上,這就使依賴IP進行主機跟蹤的機制都失效了。基於使用者行為的日誌分析也變得困難,因為一個IP被很多使用者共享,如果存在惡意的使用者行為,很難定位到發起連線的那個主機。NAT隱蔽了通訊的一端,把簡單的事情複雜化了。

  NAT一下對IP端到端模型產生了破壞。NAT通過修改IP首部的資訊變換通訊的地址。但是在這個轉換過程中只能基於一個會話單位。當一個應用需要保持多個雙向連線時,麻煩就很大。NAT不能理解多個會話之間的關聯性,無法保證轉換符合應用需要的規則。當NAT閘道器擁有多個公有IP地址時,一組關聯會話可能被分配到不同的公網地址,這通常是伺服器端無法接受的。更為嚴重的是,當公網側的主機要主動向私網側傳送資料時,NAT閘道器沒有轉換這個連線需要的關聯表,這個資料包無法到達私網側的主機。這些反方向傳送資料的連線總有應用協議的約定或在初始建立的會話中進行過協商。

(4) NAT超時機制對心跳保活

  上一節已經分析到,NAT超時機制會帶來一個問題,如果應用需要維持連線的時間大於NAT閘道器的設定,通訊就會意外中斷。因為網關回收相關轉換表資源以後,新的資料到達時就找不到相關的轉換資訊,必須建立新的連線。當這個新資料是由公網側向私網側傳送時,就會發生無法觸發新連線建立,也不能通知到私網側的主機去重建連線的情況。這時候通訊就會中斷,不能自動恢復。即使新資料是從私網側發向公網側,因為重建的會話表往往使用不同於之前的公網IP和埠地址,公網側主機也無法對應到之前的通訊上,導致使用者可感知的連線中斷。
  所以普遍的一個做法就是使用心跳保活,在一段時間沒有資料需要傳送時,主動傳送一個NAT能感知到而又沒有實際資料的保活訊息–心跳,這麼做的主要目的就是重置NAT的會話定時器。理想的情況下,客戶端應當以略小於NAT超時時間的間隔來發送心跳包。根據微信團隊測試的一些資料,一些常用網路的NAT超時時間如下表所示:

地區/網路 NAT超時時間
中國移動3G和2G 5分鐘
中國聯通2G 5分鐘
中國電信3G 大於28分鐘
美國3G 大於28分鐘
臺灣3G 大於28分鐘

5.小結

  本文簡單的總結了一些短連線的劣勢,以及幾種改進的連線方案,並引出長連線的概念和相關的使用場景,並詳細對比了keep-alive和心跳機制的不同之處,強調心跳機制對長連線保活的重要意義。並對影響心跳時間的兩個關鍵–DHCP與NAT進行了簡單的介紹。現在動態心跳的方案也越來越普及,網上已經有不少文章做了相關的分享,本文參考文獻部分也有相關的連結。如有不當之處,敬請批評指正。


參考文獻

1. TCP Keepalive HOWTO
2. 移動端IM開發需要面對的技術問題
3. 為什麼說基於TCP的移動端IM仍然需要心跳保活
4. DHCP General Operation and Client Finite State Machine
5. dhcp.figure
6. Android 2.1 - 4.1.1 Allows DHCP Lease to Expire, Keeps Using IP Address。
7. 《網路是怎麼連線的》–3.4.2節:地址轉換的基本原理
8. 《HTTP權威指南》–第4章:連線管理
9. 前端效能–淺談域名發散與域名收斂
10. Tcp Keepalive 和 HTTP Keepalive詳解
11.Android端訊息推送總結:實現原理、心跳保活、遇到的問題等
12.P2P技術詳解(一):NAT詳解——詳細原理、P2P簡介
13.知乎問答–NAT與DHCP的區別
14.一種Android端IM智慧心跳演算法的設計與實現探討

            <hr>
            

            <ul class="pager">
                
                <li class="previous">
                    <a href="/2018/03/25/okhttp-three/" data-toggle="tooltip" data-placement="top" title="" data-original-title="OkHttp原始碼解析3:RetryAndFollowUpInterceptor流程">← Previous Post</a>
                </li>
                
                
                <li class="next">
                    <a href="/2017/05/08/httpsAndroid/" data-toggle="tooltip" data-placement="top" title="" data-original-title="HTTPS原理淺析及其在Android中的使用">Next Post →</a>
                </li>
                
            </ul>

            

            

        </div>