最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

不為人知的網(wǎng)絡(luò)編程(十二):徹底搞懂TCP協(xié)議層的KeepAlive?;顧C(jī)制

2021-04-19 15:45 作者:nickkckckck  | 我要投稿

文中引用了參考資料中的部分內(nèi)容,本文參考資料詳見(jiàn)文末“參考資料”一節(jié),感謝資料分享者。

1、引言

對(duì)于IM開(kāi)發(fā)者而言,網(wǎng)絡(luò)?;钸@件事再熟悉不過(guò)了,比如這是我最近一篇有關(guān)網(wǎng)絡(luò)?;钤掝}文章《一文讀懂即時(shí)通訊應(yīng)用中的網(wǎng)絡(luò)心跳包機(jī)制:作用、原理、實(shí)現(xiàn)思路等》,以及我分享的大量代碼實(shí)戰(zhàn)編碼中也都必須要考慮這個(gè)問(wèn)題的實(shí)現(xiàn),比如最近的這篇《跟著源碼學(xué)IM(五):正確理解IM長(zhǎng)連接、心跳及重連機(jī)制,并動(dòng)手實(shí)現(xiàn)》。

對(duì)于IM這種應(yīng)用而言,應(yīng)用層的網(wǎng)絡(luò)?;畹淖钪苯愚k法就是心跳機(jī)制,比如主流的IM里有微信、QQ、釘釘、易信等等,可能代碼實(shí)現(xiàn)細(xì)節(jié)有所差異,但理論上無(wú)一例外都是這樣實(shí)現(xiàn)。(PS:沒(méi)錯(cuò),當(dāng)初微信跟運(yùn)營(yíng)商間的“信令危機(jī)”就是跟這個(gè)有關(guān))

所謂的網(wǎng)絡(luò)心跳,通常是客戶端每隔一小段時(shí)間向服務(wù)器發(fā)送一個(gè)數(shù)據(jù)包(即心跳包),通知服務(wù)器自己仍然在線(心跳包中同時(shí)可能傳輸一些必要的數(shù)據(jù))。發(fā)送心跳包,從通信層面來(lái)說(shuō)就是為了保持長(zhǎng)連接,至于這個(gè)包的內(nèi)容,是沒(méi)有什么特別規(guī)定的,但在移動(dòng)端IM中為了省流量,一般都是很小的包(比如某些第3方的IM云為了說(shuō)明心跳不費(fèi)流量,號(hào)稱1字節(jié)的心跳包)。

但經(jīng)常有人會(huì)問(wèn)到,既然TCP協(xié)議本身有KeepAlive?;钸@個(gè)東西(見(jiàn):《TCP/IP詳解 卷1?-?第23章·TCP的保活定時(shí)器》),為什么還要自已在應(yīng)用層去實(shí)現(xiàn)網(wǎng)絡(luò)?;?心跳機(jī)制呢?

沒(méi)錯(cuò),通常面視即時(shí)通訊/IM方面的程序員時(shí),這幾乎是必提問(wèn)題!

要解答這個(gè)問(wèn)題,我通常建議看看《為什么說(shuō)基于TCP的移動(dòng)端IM仍然需要心跳保活?》這篇。但限于篇幅,該篇并沒(méi)有深入探討TCP協(xié)議本身的KeepAlive機(jī)制,所以這次借本文想把TCP協(xié)議的KeepAlive保活機(jī)制給詳細(xì)的整理出來(lái),以便大家能深入其中一窺究竟。

學(xué)習(xí)交流:

- 移動(dòng)端IM開(kāi)發(fā)入門(mén)文章:《新手入門(mén)一篇就夠:從零開(kāi)發(fā)移動(dòng)端IM》

- 開(kāi)源IM框架源碼:https://github.com/JackJiang2011/MobileIMSDK

(本文已同步發(fā)布于:http://www.52im.net/thread-3506-1-1.html)

2、系列文章

本文是系列文章中的第12篇,本系列文章的大綱如下:

  • 《不為人知的網(wǎng)絡(luò)編程(一):淺析TCP協(xié)議中的疑難雜癥(上篇)》

  • 《不為人知的網(wǎng)絡(luò)編程(二):淺析TCP協(xié)議中的疑難雜癥(下篇)》

  • 《不為人知的網(wǎng)絡(luò)編程(三):關(guān)閉TCP連接時(shí)為什么會(huì)TIME_WAIT、CLOSE_WAIT》

  • 《不為人知的網(wǎng)絡(luò)編程(四):深入研究分析TCP的異常關(guān)閉》

  • 《不為人知的網(wǎng)絡(luò)編程(五):UDP的連接性和負(fù)載均衡》

  • 《不為人知的網(wǎng)絡(luò)編程(六):深入地理解UDP協(xié)議并用好它》

  • 《不為人知的網(wǎng)絡(luò)編程(七):如何讓不可靠的UDP變的可靠?》

  • 《不為人知的網(wǎng)絡(luò)編程(八):從數(shù)據(jù)傳輸層深度解密HTTP》

  • 《不為人知的網(wǎng)絡(luò)編程(九):理論聯(lián)系實(shí)際,全方位深入理解DNS》

  • 《不為人知的網(wǎng)絡(luò)編程(十):深入操作系統(tǒng),從內(nèi)核理解網(wǎng)絡(luò)包的接收過(guò)程(Linux篇)》

  • 《不為人知的網(wǎng)絡(luò)編程(十一):從底層入手,深度分析TCP連接耗時(shí)的秘密》

  • 《不為人知的網(wǎng)絡(luò)編程(十二):徹底搞懂TCP協(xié)議層的KeepAlive保活機(jī)制》(* 本文

3、TCP KeepAlive的初衷

采用TCP連接的C/S模式應(yīng)用中,當(dāng)連接的雙方在連接空閑狀態(tài)時(shí),如果任意一方意外崩潰、當(dāng)機(jī)、網(wǎng)線斷開(kāi)或路由器故障,另一方無(wú)法得知TCP連接已經(jīng)失效。

那么,連接的另一方并不知道對(duì)端的情況,它會(huì)一直維護(hù)這個(gè)連接。而作為“服務(wù)端”來(lái)說(shuō),長(zhǎng)時(shí)間的積累會(huì)導(dǎo)致非常多的半打開(kāi)連接,造成端系統(tǒng)資源的消耗和浪費(fèi),且有可能導(dǎo)致在一個(gè)無(wú)效的數(shù)據(jù)鏈路層面發(fā)送業(yè)務(wù)數(shù)據(jù),結(jié)果就是發(fā)送失敗。

所以各端要做到快速感知失敗,減少無(wú)效鏈接操作,這就有了TCP的KeepAlive?;钐綔y(cè)機(jī)制。

PS:這樣寬泛的說(shuō)TCP的KeepAlive機(jī)制的必要性,貌似還不是很有說(shuō)服力,下節(jié)將帶著具體的例子深入分析。

4、從NAT角度更具體地理解TCP KeepAlive的必要性

講到TCP的KeepAlive的必要性,多數(shù)文章都是像上節(jié)這樣比較籠統(tǒng)的進(jìn)行說(shuō)明,但對(duì)于愛(ài)刨根問(wèn)底的開(kāi)發(fā)者來(lái)說(shuō),這還遠(yuǎn)遠(yuǎn)不夠。

本節(jié)將以路由器的NAT機(jī)制這個(gè)角度來(lái)具體分析TCP協(xié)議的造物主們?cè)O(shè)計(jì)KeepAlive機(jī)制的必要性。

4.1 從NAT原理講起

狹義上,NAT分為SNAT(原地址轉(zhuǎn)換)和DNAT(目標(biāo)地址轉(zhuǎn)換),關(guān)于DNAT,有興趣的同學(xué)可以自行查閱,這里只討論SNAT。

我們都知道,路由器的最基本功能是對(duì)第三層(網(wǎng)絡(luò)層)上的IP報(bào)文進(jìn)行轉(zhuǎn)發(fā)。實(shí)際上,路由器還有很關(guān)鍵的一個(gè)功能,這便是NAT。特別是對(duì)于ISP對(duì)普通用戶鏈路上的路由器,NAT功能尤為重要。

為什么要使用NAT?

原因很簡(jiǎn)單:IPv4地址非常稀缺。上網(wǎng)需求龐大,這使得ISP不可能為每一個(gè)入網(wǎng)用戶都提供一個(gè)獨(dú)立的公網(wǎng)IP,因此通常情況下,ISP會(huì)把用戶接入局域網(wǎng),使得多個(gè)用戶共享同一個(gè)公網(wǎng)IP,而每一個(gè)用戶各分得一個(gè)局域網(wǎng)內(nèi)網(wǎng)IP。而連接公網(wǎng)和局域網(wǎng)的這臺(tái)路由器,稱之為網(wǎng)關(guān)(gateway),NAT的過(guò)程就發(fā)生在這臺(tái)網(wǎng)關(guān)路由器上。

PS:《P2P技術(shù)詳解(一):NAT詳解——詳細(xì)原理、P2P簡(jiǎn)介》這篇文章有助于更深入的理解NAT原理。

4.2 三層地址轉(zhuǎn)換

局域網(wǎng)內(nèi)的主機(jī)向公網(wǎng)發(fā)出的網(wǎng)絡(luò)層IP報(bào)文,將經(jīng)由網(wǎng)關(guān)被轉(zhuǎn)發(fā)至公網(wǎng),而在該轉(zhuǎn)發(fā)過(guò)程中發(fā)生了地址轉(zhuǎn)換。網(wǎng)關(guān)將該IP報(bào)文中的 源IP地址 從”該主機(jī)的內(nèi)網(wǎng)IP”修改為”網(wǎng)關(guān)的公網(wǎng)IP”。

比如:局域網(wǎng)主機(jī)獲得的內(nèi)網(wǎng)IP為192.168.1.100,網(wǎng)關(guān)的公網(wǎng)IP為210.177.63.2,局域網(wǎng)主機(jī)向公網(wǎng)目標(biāo)主機(jī)發(fā)出的IP報(bào)文中,源IP字段數(shù)據(jù)為192.168.1.100,在經(jīng)過(guò)網(wǎng)關(guān)時(shí),該字段數(shù)據(jù)將被修改為210.177.63.2。

為什么要這么做,相信大家已經(jīng)猜到了:公網(wǎng)上的目標(biāo)主機(jī)在收到這個(gè)IP報(bào)文后,需要知道這個(gè)IP報(bào)文的來(lái)源地址,并向該來(lái)源地址發(fā)送響應(yīng)報(bào)文,但如果不經(jīng)過(guò)NAT,目標(biāo)主機(jī)拿到的來(lái)源地址是192.168.1.100,這顯然是一個(gè)公網(wǎng)上不可訪問(wèn)到的私有地址,目標(biāo)主機(jī)無(wú)法將響應(yīng)報(bào)文發(fā)送到正確的來(lái)源主機(jī)上。開(kāi)啟了NAT之后,IP報(bào)文的來(lái)源地址被網(wǎng)關(guān)修改為210.177.63.2,這是一個(gè)公網(wǎng)地址,目標(biāo)主機(jī)將向這個(gè)地址(即網(wǎng)關(guān)路由器的公網(wǎng)地址)發(fā)送響應(yīng)報(bào)文。

但是請(qǐng)注意:如果這個(gè)IP報(bào)文的數(shù)據(jù)段不含傳輸層協(xié)議報(bào)文,而是一個(gè)pure的網(wǎng)絡(luò)層packet,來(lái)自目標(biāo)主機(jī)的響應(yīng)報(bào)文是不能被網(wǎng)關(guān)準(zhǔn)確轉(zhuǎn)發(fā)到多臺(tái)局域網(wǎng)主機(jī)中的其中一臺(tái)的。

PS:ICMP報(bào)文除外,其報(bào)頭中有Identifier字段用于標(biāo)識(shí)不同的主機(jī)或進(jìn)程,網(wǎng)關(guān)在處理Identifier時(shí)類似于下面提到的運(yùn)輸層端口。

4.3 傳輸層端口轉(zhuǎn)換表

在三層地址轉(zhuǎn)換中,我們可以保證局域網(wǎng)內(nèi)主機(jī)向公網(wǎng)發(fā)出的IP報(bào)文能順利到達(dá)目的主機(jī),但是從目的主機(jī)返回的IP報(bào)文卻不能準(zhǔn)確送至指定局域網(wǎng)主機(jī)(我們不能讓網(wǎng)關(guān)把IP報(bào)文廣播至全部局域網(wǎng)主機(jī),因?yàn)檫@樣必然會(huì)帶來(lái)安全和性能問(wèn)題)。

為了解決這個(gè)問(wèn)題,網(wǎng)關(guān)路由器需要借助傳輸層端口,通常情況下是TCP或UDP端口,由此來(lái)生成一張端口轉(zhuǎn)換表。

讓我們通過(guò)一個(gè)實(shí)例來(lái)說(shuō)明端口轉(zhuǎn)換表如何運(yùn)作:

假設(shè)局域網(wǎng)主機(jī)A192.168.1.100需要與公網(wǎng)上的目標(biāo)主機(jī)B210.199.38.2:80進(jìn)行一次TCP通信。其中A所在局域網(wǎng)的網(wǎng)關(guān)C的公網(wǎng)IP地址為210.177.63.2。

步驟如下:

1)局域網(wǎng)主機(jī)A192.168.1.100發(fā)出TCP連接請(qǐng)求,A上的TCP端口為系統(tǒng)分配的53600。該TCP握手包中,包含源地址和端口192.168.1.100:53600,目的地址和端口210.199.38.2:80。

2)網(wǎng)關(guān)C將該包的原地址和端口修改為210.177.63.2:63000,其中63000是網(wǎng)關(guān)分配的臨時(shí)端口。

3)網(wǎng)關(guān)C在端口轉(zhuǎn)換表中增加一條記錄:

4)網(wǎng)關(guān)C將修改后的TCP包發(fā)送至目的主機(jī)B。

5)目的主機(jī)B收到后,發(fā)送響應(yīng)TCP包。該響應(yīng)TCP包含有以下信息:源地址和端口210.199.38.2:80,目的地址和端口210.177.63.2:63000。

6)網(wǎng)關(guān)C收到這個(gè)來(lái)自B的響應(yīng)包后,隨即在端口轉(zhuǎn)換表中查找記錄。該記錄須符合以下條件:目的主機(jī)IP==210.199.38.2,目的主機(jī)端口==80,網(wǎng)關(guān)端口==63000。

7)網(wǎng)關(guān)C搜索到這條記錄,記錄顯示內(nèi)網(wǎng)主機(jī)IP為192.168.1.100,內(nèi)網(wǎng)主機(jī)端口為53600。

8)網(wǎng)關(guān)C將該包的目的地址和端口修改為192.168.1.100:53600。

9)網(wǎng)關(guān)C隨即將該修改后的TCP包轉(zhuǎn)發(fā)至192.168.1.100:53600,即局域網(wǎng)主機(jī)A。此時(shí)運(yùn)輸層數(shù)據(jù)的一次交換已完成。

4.4 問(wèn)題來(lái)了

在網(wǎng)關(guān)C上,由于端口數(shù)量有限(0~65535),端口轉(zhuǎn)換表的維護(hù)占用系統(tǒng)資源,因此不能無(wú)休止地向端口轉(zhuǎn)換表中增加記錄。對(duì)于過(guò)期的記錄,網(wǎng)關(guān)需要將其刪除。

如何判斷哪些是過(guò)期記錄?

網(wǎng)關(guān)認(rèn)為:一段時(shí)間內(nèi)無(wú)活動(dòng)的連接是過(guò)期的,應(yīng)定時(shí)檢測(cè)轉(zhuǎn)換表中的非活動(dòng)連接,并將之丟棄。而這個(gè)丟棄的過(guò)程,網(wǎng)關(guān)不會(huì)以任何的方式通告該連接的任何一端。

通過(guò)下圖可以更直觀的理解這個(gè)過(guò)程:?

▲ 上圖引用自《TCP?;睿═CP keepalive)》

那么問(wèn)題就來(lái)了:如果一個(gè)客戶端應(yīng)用程序由于業(yè)務(wù)需要,需要與服務(wù)端維持長(zhǎng)連接(例如基于TCP的IM聊天應(yīng)用),而如果在特別長(zhǎng)的時(shí)間內(nèi)這個(gè)連接沒(méi)有任何的數(shù)據(jù)交換,網(wǎng)關(guān)會(huì)認(rèn)為這個(gè)連接過(guò)期并將這個(gè)連接從端口轉(zhuǎn)換表中丟棄。該連接被丟棄時(shí),客戶端和服務(wù)端對(duì)此是完全無(wú)感知的。在連接被丟棄后,客戶端將收不到服務(wù)端的數(shù)據(jù)推送,客戶端發(fā)送的數(shù)據(jù)包也不能到達(dá)服務(wù)端。

一個(gè)具體的例子來(lái)感受一下這個(gè)問(wèn)題的嚴(yán)重性:

某財(cái)務(wù)應(yīng)用,在客戶端需要填寫(xiě)大量的表單數(shù)據(jù),在客戶端與服務(wù)器端建立TCP連接后,客戶端終端使用者將花費(fèi)幾分鐘甚至幾十分鐘填寫(xiě)表單相關(guān)信息,終端使用者終于填好表單所需信息后,點(diǎn)擊“提交”按鈕。

結(jié)果,這個(gè)時(shí)候由于中間設(shè)備早已經(jīng)將這個(gè)TCP連接從連接表中刪除了,其將直接丟棄這個(gè)報(bào)文或者給客戶端發(fā)送RST報(bào)文,應(yīng)用故障產(chǎn)生,這將導(dǎo)致客戶端終端使用者所有的工作將需要重新來(lái)過(guò),給使用者帶來(lái)極大的不便和損失。

4.5 解決方法

針對(duì)上述問(wèn)題,TCP協(xié)議這一層的解決方法就是利用KeepAlive機(jī)制維持長(zhǎng)連接,讓網(wǎng)關(guān)認(rèn)為我們的TCP連接是活動(dòng)的,從而避免網(wǎng)關(guān)“干掉”我們的長(zhǎng)連接。

通過(guò)NAT這個(gè)具體的例子,相信你已經(jīng)能更具體地理解TCP協(xié)議中KeepAlive?;顧C(jī)制的必要性了。

5、TCP Keepalive工作原理

5.1 技術(shù)原理

當(dāng)一個(gè) TCP 連接建立之后,啟用 TCP Keepalive 的一端便會(huì)啟動(dòng)一個(gè)計(jì)時(shí)器,當(dāng)這個(gè)計(jì)時(shí)器數(shù)值到達(dá) 0 之后(也就是經(jīng)過(guò)tcp_keep-alive_time時(shí)間后,這個(gè)參數(shù)之后會(huì)講到),一個(gè) TCP 探測(cè)包便會(huì)被發(fā)出。這個(gè) TCP 探測(cè)包是一個(gè)純 ACK 包(RFC1122#TCP Keep-Alives規(guī)范建議:不應(yīng)該包含任何數(shù)據(jù),但也可以包含1個(gè)無(wú)意義的字節(jié),比如0x0),其 Seq號(hào) 與上一個(gè)包是重復(fù)的,所以其實(shí)探測(cè)保活報(bào)文不在窗口控制范圍內(nèi)。

如果一個(gè)給定的連接在兩小時(shí)內(nèi)(默認(rèn)時(shí)長(zhǎng))沒(méi)有任何的動(dòng)作,則服務(wù)器就向客戶發(fā)一個(gè)探測(cè)報(bào)文段,客戶主機(jī)必須處于下表中的4個(gè)狀態(tài)之一。?

詳細(xì)解釋一下就是:

1)客戶主機(jī)依然正常運(yùn)行,并從服務(wù)器可達(dá)。客戶的TCP響應(yīng)正常,而服務(wù)器也知道對(duì)方是正常的,服務(wù)器在兩小時(shí)后將?;疃〞r(shí)器復(fù)位。

2)客戶主機(jī)已經(jīng)崩潰,并且關(guān)閉或者正在重新啟動(dòng)。在任何一種情況下,客戶的TCP都沒(méi)有響應(yīng)。服務(wù)端將不能收到對(duì)探測(cè)的響應(yīng),并在75秒后超時(shí)。服務(wù)器總共發(fā)送10個(gè)這樣的探測(cè) ,每個(gè)間隔75秒。如果服務(wù)器沒(méi)有收到一個(gè)響應(yīng),它就認(rèn)為客戶主機(jī)已經(jīng)關(guān)閉并終止連接。

3)客戶主機(jī)崩潰并已經(jīng)重新啟動(dòng)。服務(wù)器將收到一個(gè)對(duì)其?;钐綔y(cè)的響應(yīng),這個(gè)響應(yīng)是一個(gè)復(fù)位,使得服務(wù)器終止這個(gè)連接。

4)客戶機(jī)正常運(yùn)行,但是服務(wù)器不可達(dá),這種情況與2類似,TCP能發(fā)現(xiàn)的就是沒(méi)有收到探測(cè)的響應(yīng)。

直觀來(lái)說(shuō),TCP KeepAlive的交互過(guò)程大致如下圖所示:?

▲ 上圖引用自《TCP?;睿═CP keepalive)》

5.2 具體使用舉例

以linux內(nèi)核為例,應(yīng)用程序若想使用TCP Keepalive,需要設(shè)置SO_KEEPALIVE套接字選項(xiàng)才能生效。

對(duì)應(yīng)的,有三個(gè)重要的參數(shù):

  • 1)tcp_keepalive_time,在TCP?;畲蜷_(kāi)的情況下,最后一次數(shù)據(jù)交換到TCP發(fā)送第一個(gè)?;钐綔y(cè)包的間隔,即允許的持續(xù)空閑時(shí)長(zhǎng),或者說(shuō)每次正常發(fā)送心跳的周期,默認(rèn)值為7200s(2h);

  • 2)tcp_keepalive_probes 在tcp_keepalive_time之后,沒(méi)有接收到對(duì)方確認(rèn),繼續(xù)發(fā)送?;钐綔y(cè)包次數(shù),默認(rèn)值為9(次);

  • 3)tcp_keepalive_intvl,在tcp_keepalive_time之后,沒(méi)有接收到對(duì)方確認(rèn),繼續(xù)發(fā)送?;钐綔y(cè)包的發(fā)送頻率,默認(rèn)值為75s。

上面談的是linux內(nèi)核參數(shù)的配置,實(shí)際上其他編程語(yǔ)言有相應(yīng)的設(shè)置方法。

例如,Java的Netty服務(wù)器框架中也提供了相關(guān)接口:

ServerBootstrap b = new ServerBootstrap();

????????????b.group(bossGroup, workerGroup)

?????????????.channel(NioServerSocketChannel.class)

?????????????.option(ChannelOption.SO_BACKLOG, 100)

?????????????// 心跳監(jiān)測(cè)

?????????????.childOption(ChannelOption.SO_KEEPALIVE, true)

?????????????.handler(new LoggingHandler(LogLevel.INFO))

?????????????.childHandler(new ChannelInitializer<SocketChannel>() {

?????????????????@Override

?????????????????public void initChannel(SocketChannel ch) throwsException {

?????????????????????ch.pipeline().addLast(

?????????????????????????????new EchoServerHandler());

?????????????????}

?????????????});

????????????// Start the server.

????????????ChannelFuture f = b.bind(port).sync();

????????????// Wait until the server socket is closed.

????????????f.channel().closeFuture().sync();

PS:Java程序只能做到設(shè)置SO_KEEPALIVE選項(xiàng),至于TCP_KEEPCNT,TCP_KEEPIDLE,TCP_KEEPINTVL等參數(shù)配置,應(yīng)用層面是沒(méi)法設(shè)置的。

6、TCP KeepAlive可能導(dǎo)致的問(wèn)題

Keepalive 技術(shù)只是TCP協(xié)議中的一個(gè)可選項(xiàng)。因?yàn)椴划?dāng)?shù)呐渲每赡軙?huì)引起一些問(wèn)題,所以默認(rèn)是關(guān)閉的。

具體來(lái)說(shuō),可能導(dǎo)致下列問(wèn)題:

  • 1)在短暫的故障期間,Keepalive設(shè)置不合理時(shí)可能會(huì)因?yàn)槎虝旱木W(wǎng)絡(luò)波動(dòng)而斷開(kāi)健康的TCP連接;

  • 2)需要消耗額外的寬帶和流量(對(duì)于現(xiàn)在這個(gè)時(shí)代來(lái)說(shuō),這貌似已經(jīng)不是問(wèn)題了);

  • 3)在以流量計(jì)費(fèi)的互聯(lián)網(wǎng)環(huán)境中增加了費(fèi)用開(kāi)銷。

7、TCP KeepAlive在移動(dòng)網(wǎng)絡(luò)時(shí)代的局限性

不可否認(rèn),TCP協(xié)議作為T(mén)CP/IP協(xié)議族中最重要部分,對(duì)互聯(lián)的發(fā)展確實(shí)功不可沒(méi)(見(jiàn):《技術(shù)往事:改變世界的TCP/IP協(xié)議(珍貴多圖、手機(jī)慎點(diǎn))》)。

但如今移動(dòng)網(wǎng)絡(luò)時(shí)代,無(wú)線通信越來(lái)越普及,作為上個(gè)世紀(jì)中期發(fā)明的TCP協(xié)議來(lái)說(shuō),客觀的講,在某些場(chǎng)景下確實(shí)有先天不足(見(jiàn):《5G時(shí)代已經(jīng)到來(lái),TCP/IP老矣,尚能飯否?》)。

那么,又回到了本文開(kāi)頭的問(wèn)題——“既然TCP協(xié)議本身有KeepAlive,為什么還要自已在應(yīng)用層實(shí)現(xiàn)網(wǎng)絡(luò)保活/心跳機(jī)制?”。

以移動(dòng)端IM應(yīng)用為例:

  • 1)一方面,運(yùn)營(yíng)商ISP的網(wǎng)絡(luò)資源更為稀缺,TCP協(xié)議默認(rèn)2小時(shí)的KeepAlive基本不可能實(shí)現(xiàn)IM長(zhǎng)連接“保活”(為了提升無(wú)線網(wǎng)絡(luò)資源的利用率,運(yùn)營(yíng)商長(zhǎng)則幾分鐘,短則數(shù)十秒就有可能回收空閑的網(wǎng)絡(luò)連接)。

  • 2)另一面,無(wú)線網(wǎng)絡(luò)本身存在弱網(wǎng)問(wèn)題,即使TCP連接是“好的”,但實(shí)際上處于“假死”狀態(tài),也無(wú)法起到長(zhǎng)連接該有的作用。

所以說(shuō),IM應(yīng)用層自已做網(wǎng)絡(luò)?;睿ㄐ奶鴻C(jī)制)是不可避免的。

有關(guān)這方面的更多資料,有興趣,可以深入閱讀下面這幾篇:

《為何基于TCP協(xié)議的移動(dòng)端IM仍然需要心跳?;顧C(jī)制?》

《移動(dòng)端IM開(kāi)發(fā)者必讀(一):通俗易懂,理解移動(dòng)網(wǎng)絡(luò)的“弱”和“慢”》

《移動(dòng)端IM開(kāi)發(fā)者必讀(二):史上最全移動(dòng)弱網(wǎng)絡(luò)優(yōu)化方法總結(jié)》

《IM開(kāi)發(fā)者的零基礎(chǔ)通信技術(shù)入門(mén)(十三):為什么手機(jī)信號(hào)差?一文即懂!》

《IM開(kāi)發(fā)者的零基礎(chǔ)通信技術(shù)入門(mén)(十四):高鐵上無(wú)線上網(wǎng)有多難?一文即懂!》

8、知識(shí)拓展:TCP Keepalive和HTTP Keep-Alive有什么區(qū)別?

很多人會(huì)把TCP Keepalive 和 HTTP Keep-Alive 這兩個(gè)概念搞混淆。

這里簡(jiǎn)單介紹下HTTP Keep-Alive 。

在HTTP/1.0中,默認(rèn)使用的是短連接。也就是說(shuō),瀏覽器和服務(wù)器每進(jìn)行一次HTTP操作,就建立一次連接,但任務(wù)結(jié)束就中斷連接。如果客戶端瀏覽器訪問(wèn)的某個(gè)HTML或其他類型的 Web頁(yè)中包含有其他的Web資源,如JavaScript文件、圖像文件、CSS文件等;當(dāng)瀏覽器每遇到這樣一個(gè)Web資源,就會(huì)建立一個(gè)HTTP會(huì)話。

但從 HTTP/1.1起,默認(rèn)使用長(zhǎng)連接,用以保持連接特性。使用長(zhǎng)連接的HTTP協(xié)議,會(huì)在響應(yīng)頭加上Connection、Keep-Alive字段。

如下圖所示:

HTTP 1.0 和 1.1 在 TCP連接使用方面的差異如下圖所示:?

通俗地總結(jié)一下:

  • 1)HTTP的Keep-Alive是為了讓TCP連接活得更久一點(diǎn),在發(fā)起多個(gè)http請(qǐng)求時(shí)能復(fù)用同一個(gè)連接,提高通信效率;

  • 2)TCP的KeepAlive機(jī)制意圖在于探測(cè)連接的對(duì)端是否存活,是一種檢測(cè)TCP連接狀況的保鮮機(jī)制。

9、參考資料

[1]?TCP保活(TCP keepalive)

[2]?TCP協(xié)議的KeepAlive機(jī)制與HeartBeat心跳包

[3]?HTTP keep-alive和TCP keepalive的區(qū)別,你了解嗎?

[4]?TCP KeepAlive 與 HTTP Keep-Alive 區(qū)別

[5]?tcp連接探測(cè)Keepalive和心跳包

[6]?TCP keepalive的探究 (1) : NAT和?;顧C(jī)制

[7]?理解TCP長(zhǎng)連接(Keepalive)

[8]?為何基于TCP協(xié)議的移動(dòng)端IM仍然需要心跳保活機(jī)制?

[9]?移動(dòng)端IM開(kāi)發(fā)者必讀(二):史上最全移動(dòng)弱網(wǎng)絡(luò)優(yōu)化方法總結(jié)

[10]?IM開(kāi)發(fā)者的零基礎(chǔ)通信技術(shù)入門(mén)(十三):為什么手機(jī)信號(hào)差?一文即懂!

附錄:更多網(wǎng)絡(luò)編程精華文章

[1] 網(wǎng)絡(luò)編程(基礎(chǔ))資料:

《網(wǎng)絡(luò)編程懶人入門(mén)(一):快速理解網(wǎng)絡(luò)通信協(xié)議(上篇)》

《網(wǎng)絡(luò)編程懶人入門(mén)(二):快速理解網(wǎng)絡(luò)通信協(xié)議(下篇)》

《網(wǎng)絡(luò)編程懶人入門(mén)(三):快速理解TCP協(xié)議一篇就夠》

《網(wǎng)絡(luò)編程懶人入門(mén)(四):快速理解TCP和UDP的差異》

《網(wǎng)絡(luò)編程懶人入門(mén)(五):快速理解為什么說(shuō)UDP有時(shí)比TCP更有優(yōu)勢(shì)》

《網(wǎng)絡(luò)編程懶人入門(mén)(六):史上最通俗的集線器、交換機(jī)、路由器功能原理入門(mén)》

《網(wǎng)絡(luò)編程懶人入門(mén)(七):深入淺出,全面理解HTTP協(xié)議》

《網(wǎng)絡(luò)編程懶人入門(mén)(八):手把手教你寫(xiě)基于TCP的Socket長(zhǎng)連接》

《網(wǎng)絡(luò)編程懶人入門(mén)(九):通俗講解,有了IP地址,為何還要用MAC地址?》

《網(wǎng)絡(luò)編程懶人入門(mén)(十):一泡尿的時(shí)間,快速讀懂QUIC協(xié)議》

《網(wǎng)絡(luò)編程懶人入門(mén)(十一):一文讀懂什么是IPv6》

《網(wǎng)絡(luò)編程懶人入門(mén)(十二):快速讀懂Http/3協(xié)議,一篇就夠!》

《腦殘式網(wǎng)絡(luò)編程入門(mén)(一):跟著動(dòng)畫(huà)來(lái)學(xué)TCP三次握手和四次揮手》

《腦殘式網(wǎng)絡(luò)編程入門(mén)(二):我們?cè)谧x寫(xiě)Socket時(shí),究竟在讀寫(xiě)什么?》

《腦殘式網(wǎng)絡(luò)編程入門(mén)(三):HTTP協(xié)議必知必會(huì)的一些知識(shí)》

《腦殘式網(wǎng)絡(luò)編程入門(mén)(四):快速理解HTTP/2的服務(wù)器推送(Server Push)》

《腦殘式網(wǎng)絡(luò)編程入門(mén)(五):每天都在用的Ping命令,它到底是什么?》

《腦殘式網(wǎng)絡(luò)編程入門(mén)(六):什么是公網(wǎng)IP和內(nèi)網(wǎng)IP?NAT轉(zhuǎn)換又是什么鬼?》

《腦殘式網(wǎng)絡(luò)編程入門(mén)(七):面視必備,史上最通俗計(jì)算機(jī)網(wǎng)絡(luò)分層詳解》

《腦殘式網(wǎng)絡(luò)編程入門(mén)(八):你真的了解127.0.0.1和0.0.0.0的區(qū)別?》

《腦殘式網(wǎng)絡(luò)編程入門(mén)(九):面試必考,史上最通俗大小端字節(jié)序詳解》

《網(wǎng)絡(luò)編程入門(mén)從未如此簡(jiǎn)單(一):假如你來(lái)設(shè)計(jì)網(wǎng)絡(luò),會(huì)怎么做?》

《網(wǎng)絡(luò)編程入門(mén)從未如此簡(jiǎn)單(二):假如你來(lái)設(shè)計(jì)TCP協(xié)議,會(huì)怎么做?》

>>?更多同類文章 ……

[2] 網(wǎng)絡(luò)編程(高階)資料:

《高性能網(wǎng)絡(luò)編程(一):?jiǎn)闻_(tái)服務(wù)器并發(fā)TCP連接數(shù)到底可以有多少》

《高性能網(wǎng)絡(luò)編程(二):上一個(gè)10年,著名的C10K并發(fā)連接問(wèn)題》

《高性能網(wǎng)絡(luò)編程(三):下一個(gè)10年,是時(shí)候考慮C10M并發(fā)問(wèn)題了》

《高性能網(wǎng)絡(luò)編程(四):從C10K到C10M高性能網(wǎng)絡(luò)應(yīng)用的理論探索》

《高性能網(wǎng)絡(luò)編程(五):一文讀懂高性能網(wǎng)絡(luò)編程中的I/O模型》

《高性能網(wǎng)絡(luò)編程(六):一文讀懂高性能網(wǎng)絡(luò)編程中的線程模型》

《高性能網(wǎng)絡(luò)編程(七):到底什么是高并發(fā)?一文即懂!》

《不為人知的網(wǎng)絡(luò)編程(一):淺析TCP協(xié)議中的疑難雜癥(上篇)》

《不為人知的網(wǎng)絡(luò)編程(二):淺析TCP協(xié)議中的疑難雜癥(下篇)》

《不為人知的網(wǎng)絡(luò)編程(三):關(guān)閉TCP連接時(shí)為什么會(huì)TIME_WAIT、CLOSE_WAIT》

《不為人知的網(wǎng)絡(luò)編程(四):深入研究分析TCP的異常關(guān)閉》

《不為人知的網(wǎng)絡(luò)編程(五):UDP的連接性和負(fù)載均衡》

《不為人知的網(wǎng)絡(luò)編程(六):深入地理解UDP協(xié)議并用好它》

《不為人知的網(wǎng)絡(luò)編程(七):如何讓不可靠的UDP變的可靠?》

《不為人知的網(wǎng)絡(luò)編程(八):從數(shù)據(jù)傳輸層深度解密HTTP》

《不為人知的網(wǎng)絡(luò)編程(九):理論聯(lián)系實(shí)際,全方位深入理解DNS》

《不為人知的網(wǎng)絡(luò)編程(十):深入操作系統(tǒng),從內(nèi)核理解網(wǎng)絡(luò)包的接收過(guò)程(Linux篇)》

《不為人知的網(wǎng)絡(luò)編程(十一):從底層入手,深度分析TCP連接耗時(shí)的秘密》

《不為人知的網(wǎng)絡(luò)編程(十二):徹底搞懂TCP協(xié)議層的KeepAlive?;顧C(jī)制》

《IM開(kāi)發(fā)者的零基礎(chǔ)通信技術(shù)入門(mén)(十一):為什么WiFi信號(hào)差?一文即懂!》

《IM開(kāi)發(fā)者的零基礎(chǔ)通信技術(shù)入門(mén)(十二):上網(wǎng)卡頓?網(wǎng)絡(luò)掉線?一文即懂!》

《IM開(kāi)發(fā)者的零基礎(chǔ)通信技術(shù)入門(mén)(十三):為什么手機(jī)信號(hào)差?一文即懂!》

《IM開(kāi)發(fā)者的零基礎(chǔ)通信技術(shù)入門(mén)(十四):高鐵上無(wú)線上網(wǎng)有多難?一文即懂!》

《IM開(kāi)發(fā)者的零基礎(chǔ)通信技術(shù)入門(mén)(十五):理解定位技術(shù),一篇就夠》

>>?更多同類文章 ……

本文已同步發(fā)布于“即時(shí)通訊技術(shù)圈”公眾號(hào)。同步發(fā)布鏈接是:http://www.52im.net/thread-3506-1-1.html


不為人知的網(wǎng)絡(luò)編程(十二):徹底搞懂TCP協(xié)議層的KeepAlive保活機(jī)制的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
宁南县| 青铜峡市| 佛坪县| 永顺县| 江北区| 平邑县| 嘉善县| 顺义区| 蒲城县| 河源市| 黄山市| 阿勒泰市| 江门市| 天台县| 二连浩特市| 福安市| 白沙| 綦江县| 乌拉特后旗| 汤阴县| 彭水| 南昌市| 锦屏县| 彰武县| 资中县| 襄汾县| 石门县| 屯门区| 巴南区| 广西| 武义县| 塘沽区| 连城县| 榆树市| 莱芜市| 通化市| 凤凰县| 宁南县| 南阳市| 广安市| 乡城县|