文中引用了參考資料中的部分內(nèi)容,本文參考資料詳見文末“參考資料”一節(jié),感謝資料分享者。
1、引言
對于IM開發(fā)者而言,網(wǎng)絡(luò)保活這件事再熟悉不過了,比如這是我最近一篇有關(guān)網(wǎng)絡(luò)保活話題文章《一文讀懂即時(shí)通訊應(yīng)用中的網(wǎng)絡(luò)心跳包機(jī)制:作用、原理、實(shí)現(xiàn)思路等》,以及我分享的大量代碼實(shí)戰(zhàn)編碼中也都必須要考慮這個(gè)問題的實(shí)現(xiàn),比如最近的這篇《跟著源碼學(xué)IM(五):正確理解IM長連接、心跳及重連機(jī)制,并動手實(shí)現(xiàn)》。
對于IM這種應(yīng)用而言,應(yīng)用層的網(wǎng)絡(luò)保活的最直接辦法就是心跳機(jī)制,比如主流的IM里有微信、QQ、釘釘、易信等等,可能代碼實(shí)現(xiàn)細(xì)節(jié)有所差異,但理論上無一例外都是這樣實(shí)現(xiàn)。(PS:沒錯(cuò),當(dāng)初微信跟運(yùn)營商間的“信令危機(jī)”就是跟這個(gè)有關(guān))
所謂的網(wǎng)絡(luò)心跳,通常是客戶端每隔一小段時(shí)間向服務(wù)器發(fā)送一個(gè)數(shù)據(jù)包(即心跳包),通知服務(wù)器自己仍然在線(心跳包中同時(shí)可能傳輸一些必要的數(shù)據(jù))。發(fā)送心跳包,從通信層面來說就是為了保持長連接,至于這個(gè)包的內(nèi)容,是沒有什么特別規(guī)定的,但在移動端IM中為了省流量,一般都是很小的包(比如某些第3方的IM云為了說明心跳不費(fèi)流量,號稱1字節(jié)的心跳包)。
但經(jīng)常有人會問到,既然TCP協(xié)議本身有KeepAlive保活這個(gè)東西(見:《TCP/IP詳解 卷1 - 第23章·TCP的保活定時(shí)器》),為什么還要自已在應(yīng)用層去實(shí)現(xiàn)網(wǎng)絡(luò)保活/心跳機(jī)制呢?
沒錯(cuò),通常面視即時(shí)通訊/IM方面的程序員時(shí),這幾乎是必提問題!
要解答這個(gè)問題,我通常建議看看《為什么說基于TCP的移動端IM仍然需要心跳保活?》這篇。但限于篇幅,該篇并沒有深入探討TCP協(xié)議本身的KeepAlive機(jī)制,所以這次借本文想把TCP協(xié)議的KeepAlive保活機(jī)制給詳細(xì)的整理出來,以便大家能深入其中一窺究竟。
學(xué)習(xí)交流:
- 即時(shí)通訊/推送技術(shù)開發(fā)交流5群:215477170 [推薦]
- 移動端IM開發(fā)入門文章:《新手入門一篇就夠:從零開發(fā)移動端IM》
- 開源IM框架源碼:https://github.com/JackJiang2011/MobileIMSDK
(本文已同步發(fā)布于:http://www.52im.net/thread-3506-1-1.html)
2、系列文章
本文是系列文章中的第12篇,本系列文章的大綱如下:
3、TCP KeepAlive的初衷
采用TCP連接的C/S模式應(yīng)用中,當(dāng)連接的雙方在連接空閑狀態(tài)時(shí),如果任意一方意外崩潰、當(dāng)機(jī)、網(wǎng)線斷開或路由器故障,另一方無法得知TCP連接已經(jīng)失效。
那么,連接的另一方并不知道對端的情況,它會一直維護(hù)這個(gè)連接。而作為“服務(wù)端”來說,長時(shí)間的積累會導(dǎo)致非常多的半打開連接,造成端系統(tǒng)資源的消耗和浪費(fèi),且有可能導(dǎo)致在一個(gè)無效的數(shù)據(jù)鏈路層面發(fā)送業(yè)務(wù)數(shù)據(jù),結(jié)果就是發(fā)送失敗。
所以各端要做到快速感知失敗,減少無效鏈接操作,這就有了TCP的KeepAlive保活探測機(jī)制。
PS:這樣寬泛的說TCP的KeepAlive機(jī)制的必要性,貌似還不是很有說服力,下節(jié)將帶著具體的例子深入分析。
4、從NAT角度更具體地理解TCP KeepAlive的必要性
講到TCP的KeepAlive的必要性,多數(shù)文章都是像上節(jié)這樣比較籠統(tǒng)的進(jìn)行說明,但對于愛刨根問底的開發(fā)者來說,這還遠(yuǎn)遠(yuǎn)不夠。
本節(jié)將以路由器的NAT機(jī)制這個(gè)角度來具體分析TCP協(xié)議的造物主們設(shè)計(jì)KeepAlive機(jī)制的必要性。
4.1 從NAT原理講起
狹義上,NAT分為SNAT(原地址轉(zhuǎn)換)和DNAT(目標(biāo)地址轉(zhuǎn)換),關(guān)于DNAT,有興趣的同學(xué)可以自行查閱,這里只討論SNAT。
我們都知道,路由器的最基本功能是對第三層(網(wǎng)絡(luò)層)上的IP報(bào)文進(jìn)行轉(zhuǎn)發(fā)。實(shí)際上,路由器還有很關(guān)鍵的一個(gè)功能,這便是NAT。特別是對于ISP對普通用戶鏈路上的路由器,NAT功能尤為重要。
為什么要使用NAT?
原因很簡單:IPv4地址非常稀缺。上網(wǎng)需求龐大,這使得ISP不可能為每一個(gè)入網(wǎng)用戶都提供一個(gè)獨(dú)立的公網(wǎng)IP,因此通常情況下,ISP會把用戶接入局域網(wǎng),使得多個(gè)用戶共享同一個(gè)公網(wǎng)IP,而每一個(gè)用戶各分得一個(gè)局域網(wǎng)內(nèi)網(wǎng)IP。而連接公網(wǎng)和局域網(wǎng)的這臺路由器,稱之為網(wǎng)關(guān)(gateway),NAT的過程就發(fā)生在這臺網(wǎng)關(guān)路由器上。
PS:《P2P技術(shù)詳解(一):NAT詳解——詳細(xì)原理、P2P簡介》這篇文章有助于更深入的理解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ā)過程中發(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)過網(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)文的來源地址,并向該來源地址發(fā)送響應(yīng)報(bào)文,但如果不經(jīng)過NAT,目標(biāo)主機(jī)拿到的來源地址是192.168.1.100,這顯然是一個(gè)公網(wǎng)上不可訪問到的私有地址,目標(biāo)主機(jī)無法將響應(yīng)報(bào)文發(fā)送到正確的來源主機(jī)上。開啟了NAT之后,IP報(bào)文的來源地址被網(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)文。
但是請注意:如果這個(gè)IP報(bào)文的數(shù)據(jù)段不含傳輸層協(xié)議報(bào)文,而是一個(gè)pure的網(wǎng)絡(luò)層packet,來自目標(biāo)主機(jī)的響應(yīng)報(bào)文是不能被網(wǎng)關(guān)準(zhǔn)確轉(zhuǎn)發(fā)到多臺局域網(wǎng)主機(jī)中的其中一臺的。
PS:ICMP報(bào)文除外,其報(bào)頭中有Identifier字段用于標(biāo)識不同的主機(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)檫@樣必然會帶來安全和性能問題)。
為了解決這個(gè)問題,網(wǎng)關(guān)路由器需要借助傳輸層端口,通常情況下是TCP或UDP端口,由此來生成一張端口轉(zhuǎn)換表。
讓我們通過一個(gè)實(shí)例來說明端口轉(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連接請求,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è)來自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ǎng)關(guān)C上,由于端口數(shù)量有限(0~65535),端口轉(zhuǎn)換表的維護(hù)占用系統(tǒng)資源,因此不能無休止地向端口轉(zhuǎn)換表中增加記錄。對于過期的記錄,網(wǎng)關(guān)需要將其刪除。
如何判斷哪些是過期記錄?
網(wǎng)關(guān)認(rèn)為:一段時(shí)間內(nèi)無活動的連接是過期的,應(yīng)定時(shí)檢測轉(zhuǎn)換表中的非活動連接,并將之丟棄。而這個(gè)丟棄的過程,網(wǎng)關(guān)不會以任何的方式通告該連接的任何一端。
通過下圖可以更直觀的理解這個(gè)過程:
▲ 上圖引用自《TCP保活(TCP keepalive)》
那么問題就來了:如果一個(gè)客戶端應(yīng)用程序由于業(yè)務(wù)需要,需要與服務(wù)端維持長連接(例如基于TCP的IM聊天應(yīng)用),而如果在特別長的時(shí)間內(nèi)這個(gè)連接沒有任何的數(shù)據(jù)交換,網(wǎng)關(guān)會認(rèn)為這個(gè)連接過期并將這個(gè)連接從端口轉(zhuǎn)換表中丟棄。該連接被丟棄時(shí),客戶端和服務(wù)端對此是完全無感知的。在連接被丟棄后,客戶端將收不到服務(wù)端的數(shù)據(jù)推送,客戶端發(fā)送的數(shù)據(jù)包也不能到達(dá)服務(wù)端。
一個(gè)具體的例子來感受一下這個(gè)問題的嚴(yán)重性:
某財(cái)務(wù)應(yīng)用,在客戶端需要填寫大量的表單數(shù)據(jù),在客戶端與服務(wù)器端建立TCP連接后,客戶端終端使用者將花費(fèi)幾分鐘甚至幾十分鐘填寫表單相關(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)致客戶端終端使用者所有的工作將需要重新來過,給使用者帶來極大的不便和損失。
4.5 解決方法
針對上述問題,TCP協(xié)議這一層的解決方法就是利用KeepAlive機(jī)制維持長連接,讓網(wǎng)關(guān)認(rèn)為我們的TCP連接是活動的,從而避免網(wǎng)關(guān)“干掉”我們的長連接。
通過NAT這個(gè)具體的例子,相信你已經(jīng)能更具體地理解TCP協(xié)議中KeepAlive保活機(jī)制的必要性了。
5、TCP Keepalive工作原理
5.1 技術(shù)原理
當(dāng)一個(gè) TCP 連接建立之后,啟用 TCP Keepalive 的一端便會啟動一個(gè)計(jì)時(shí)器,當(dāng)這個(gè)計(jì)時(shí)器數(shù)值到達(dá) 0 之后(也就是經(jīng)過tcp_keep-alive_time時(shí)間后,這個(gè)參數(shù)之后會講到),一個(gè) TCP 探測包便會被發(fā)出。這個(gè) TCP 探測包是一個(gè)純 ACK 包(RFC1122#TCP Keep-Alives規(guī)范建議:不應(yīng)該包含任何數(shù)據(jù),但也可以包含1個(gè)無意義的字節(jié),比如0x0),其 Seq號 與上一個(gè)包是重復(fù)的,所以其實(shí)探測保活報(bào)文不在窗口控制范圍內(nèi)。
如果一個(gè)給定的連接在兩小時(shí)內(nèi)(默認(rèn)時(shí)長)沒有任何的動作,則服務(wù)器就向客戶發(fā)一個(gè)探測報(bào)文段,客戶主機(jī)必須處于下表中的4個(gè)狀態(tài)之一。
詳細(xì)解釋一下就是:
1)客戶主機(jī)依然正常運(yùn)行,并從服務(wù)器可達(dá)。客戶的TCP響應(yīng)正常,而服務(wù)器也知道對方是正常的,服務(wù)器在兩小時(shí)后將保活定時(shí)器復(fù)位。
2)客戶主機(jī)已經(jīng)崩潰,并且關(guān)閉或者正在重新啟動。在任何一種情況下,客戶的TCP都沒有響應(yīng)。服務(wù)端將不能收到對探測的響應(yīng),并在75秒后超時(shí)。服務(wù)器總共發(fā)送10個(gè)這樣的探測 ,每個(gè)間隔75秒。如果服務(wù)器沒有收到一個(gè)響應(yīng),它就認(rèn)為客戶主機(jī)已經(jīng)關(guān)閉并終止連接。
3)客戶主機(jī)崩潰并已經(jīng)重新啟動。服務(wù)器將收到一個(gè)對其保活探測的響應(yīng),這個(gè)響應(yīng)是一個(gè)復(fù)位,使得服務(wù)器終止這個(gè)連接。
4)客戶機(jī)正常運(yùn)行,但是服務(wù)器不可達(dá),這種情況與2類似,TCP能發(fā)現(xiàn)的就是沒有收到探測的響應(yīng)。
直觀來說,TCP KeepAlive的交互過程大致如下圖所示:
▲ 上圖引用自《TCP保活(TCP keepalive)》
5.2 具體使用舉例
以linux內(nèi)核為例,應(yīng)用程序若想使用TCP Keepalive,需要設(shè)置SO_KEEPALIVE套接字選項(xiàng)才能生效。
對應(yīng)的,有三個(gè)重要的參數(shù):
- 1)tcp_keepalive_time,在TCP保活打開的情況下,最后一次數(shù)據(jù)交換到TCP發(fā)送第一個(gè)保活探測包的間隔,即允許的持續(xù)空閑時(shí)長,或者說每次正常發(fā)送心跳的周期,默認(rèn)值為7200s(2h);
- 2)tcp_keepalive_probes 在tcp_keepalive_time之后,沒有接收到對方確認(rèn),繼續(xù)發(fā)送保活探測包次數(shù),默認(rèn)值為9(次);
- 3)tcp_keepalive_intvl,在tcp_keepalive_time之后,沒有接收到對方確認(rèn),繼續(xù)發(fā)送保活探測包的發(fā)送頻率,默認(rèn)值為75s。
上面談的是linux內(nèi)核參數(shù)的配置,實(shí)際上其他編程語言有相應(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)測
.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)用層面是沒法設(shè)置的。
6、TCP KeepAlive可能導(dǎo)致的問題
Keepalive 技術(shù)只是TCP協(xié)議中的一個(gè)可選項(xiàng)。因?yàn)椴划?dāng)?shù)呐渲每赡軙鹨恍﹩栴},所以默認(rèn)是關(guān)閉的。
具體來說,可能導(dǎo)致下列問題:
- 1)在短暫的故障期間,Keepalive設(shè)置不合理時(shí)可能會因?yàn)槎虝旱木W(wǎng)絡(luò)波動而斷開健康的TCP連接;
- 2)需要消耗額外的寬帶和流量(對于現(xiàn)在這個(gè)時(shí)代來說,這貌似已經(jīng)不是問題了);
- 3)在以流量計(jì)費(fèi)的互聯(lián)網(wǎng)環(huán)境中增加了費(fèi)用開銷。
7、TCP KeepAlive在移動網(wǎng)絡(luò)時(shí)代的局限性
不可否認(rèn),TCP協(xié)議作為TCP/IP協(xié)議族中最重要部分,對互聯(lián)的發(fā)展確實(shí)功不可沒(見:《技術(shù)往事:改變世界的TCP/IP協(xié)議(珍貴多圖、手機(jī)慎點(diǎn))》)。
但如今移動網(wǎng)絡(luò)時(shí)代,無線通信越來越普及,作為上個(gè)世紀(jì)中期發(fā)明的TCP協(xié)議來說,客觀的講,在某些場景下確實(shí)有先天不足(見:《5G時(shí)代已經(jīng)到來,TCP/IP老矣,尚能飯否?》)。
那么,又回到了本文開頭的問題——“既然TCP協(xié)議本身有KeepAlive,為什么還要自已在應(yīng)用層實(shí)現(xiàn)網(wǎng)絡(luò)保活/心跳機(jī)制?”。
以移動端IM應(yīng)用為例:
- 1)一方面,運(yùn)營商ISP的網(wǎng)絡(luò)資源更為稀缺,TCP協(xié)議默認(rèn)2小時(shí)的KeepAlive基本不可能實(shí)現(xiàn)IM長連接“保活”(為了提升無線網(wǎng)絡(luò)資源的利用率,運(yùn)營商長則幾分鐘,短則數(shù)十秒就有可能回收空閑的網(wǎng)絡(luò)連接)。
- 2)另一面,無線網(wǎng)絡(luò)本身存在弱網(wǎng)問題,即使TCP連接是“好的”,但實(shí)際上處于“假死”狀態(tài),也無法起到長連接該有的作用。
所以說,IM應(yīng)用層自已做網(wǎng)絡(luò)保活(心跳機(jī)制)是不可避免的。
有關(guān)這方面的更多資料,有興趣,可以深入閱讀下面這幾篇:
《為何基于TCP協(xié)議的移動端IM仍然需要心跳保活機(jī)制?》
《移動端IM開發(fā)者必讀(一):通俗易懂,理解移動網(wǎng)絡(luò)的“弱”和“慢”》
《移動端IM開發(fā)者必讀(二):史上最全移動弱網(wǎng)絡(luò)優(yōu)化方法總結(jié)》
《IM開發(fā)者的零基礎(chǔ)通信技術(shù)入門(十三):為什么手機(jī)信號差?一文即懂!》
《IM開發(fā)者的零基礎(chǔ)通信技術(shù)入門(十四):高鐵上無線上網(wǎng)有多難?一文即懂!》
8、知識拓展:TCP Keepalive和HTTP Keep-Alive有什么區(qū)別?
很多人會把TCP Keepalive 和 HTTP Keep-Alive 這兩個(gè)概念搞混淆。
這里簡單介紹下HTTP Keep-Alive 。
在HTTP/1.0中,默認(rèn)使用的是短連接。也就是說,瀏覽器和服務(wù)器每進(jìn)行一次HTTP操作,就建立一次連接,但任務(wù)結(jié)束就中斷連接。如果客戶端瀏覽器訪問的某個(gè)HTML或其他類型的 Web頁中包含有其他的Web資源,如JavaScript文件、圖像文件、CSS文件等;當(dāng)瀏覽器每遇到這樣一個(gè)Web資源,就會建立一個(gè)HTTP會話。
但從 HTTP/1.1起,默認(rèn)使用長連接,用以保持連接特性。使用長連接的HTTP協(xié)議,會在響應(yīng)頭加上Connection、Keep-Alive字段。
如下圖所示:
HTTP 1.0 和 1.1 在 TCP連接使用方面的差異如下圖所示:
通俗地總結(jié)一下:
- 1)HTTP的Keep-Alive是為了讓TCP連接活得更久一點(diǎn),在發(fā)起多個(gè)http請求時(shí)能復(fù)用同一個(gè)連接,提高通信效率;
- 2)TCP的KeepAlive機(jī)制意圖在于探測連接的對端是否存活,是一種檢測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連接探測Keepalive和心跳包
[6] TCP keepalive的探究 (1) : NAT和保活機(jī)制
[7] 理解TCP長連接(Keepalive)
[8] 為何基于TCP協(xié)議的移動端IM仍然需要心跳保活機(jī)制?
[9] 移動端IM開發(fā)者必讀(二):史上最全移動弱網(wǎng)絡(luò)優(yōu)化方法總結(jié)
[10] IM開發(fā)者的零基礎(chǔ)通信技術(shù)入門(十三):為什么手機(jī)信號差?一文即懂!
附錄:更多網(wǎng)絡(luò)編程精華文章
[1] 網(wǎng)絡(luò)編程(基礎(chǔ))資料:
《網(wǎng)絡(luò)編程懶人入門(一):快速理解網(wǎng)絡(luò)通信協(xié)議(上篇)》
《網(wǎng)絡(luò)編程懶人入門(二):快速理解網(wǎng)絡(luò)通信協(xié)議(下篇)》
《網(wǎng)絡(luò)編程懶人入門(三):快速理解TCP協(xié)議一篇就夠》
《網(wǎng)絡(luò)編程懶人入門(四):快速理解TCP和UDP的差異》
《網(wǎng)絡(luò)編程懶人入門(五):快速理解為什么說UDP有時(shí)比TCP更有優(yōu)勢》
《網(wǎng)絡(luò)編程懶人入門(六):史上最通俗的集線器、交換機(jī)、路由器功能原理入門》
《網(wǎng)絡(luò)編程懶人入門(七):深入淺出,全面理解HTTP協(xié)議》
《網(wǎng)絡(luò)編程懶人入門(八):手把手教你寫基于TCP的Socket長連接》
《網(wǎng)絡(luò)編程懶人入門(九):通俗講解,有了IP地址,為何還要用MAC地址?》
《網(wǎng)絡(luò)編程懶人入門(十):一泡尿的時(shí)間,快速讀懂QUIC協(xié)議》
《網(wǎng)絡(luò)編程懶人入門(十一):一文讀懂什么是IPv6》
《網(wǎng)絡(luò)編程懶人入門(十二):快速讀懂Http/3協(xié)議,一篇就夠!》
《腦殘式網(wǎng)絡(luò)編程入門(一):跟著動畫來學(xué)TCP三次握手和四次揮手》
《腦殘式網(wǎng)絡(luò)編程入門(二):我們在讀寫Socket時(shí),究竟在讀寫什么?》
《腦殘式網(wǎng)絡(luò)編程入門(三):HTTP協(xié)議必知必會的一些知識》
《腦殘式網(wǎng)絡(luò)編程入門(四):快速理解HTTP/2的服務(wù)器推送(Server Push)》
《腦殘式網(wǎng)絡(luò)編程入門(五):每天都在用的Ping命令,它到底是什么?》
《腦殘式網(wǎng)絡(luò)編程入門(六):什么是公網(wǎng)IP和內(nèi)網(wǎng)IP?NAT轉(zhuǎn)換又是什么鬼?》
《腦殘式網(wǎng)絡(luò)編程入門(七):面視必備,史上最通俗計(jì)算機(jī)網(wǎng)絡(luò)分層詳解》
《腦殘式網(wǎng)絡(luò)編程入門(八):你真的了解127.0.0.1和0.0.0.0的區(qū)別?》
《腦殘式網(wǎng)絡(luò)編程入門(九):面試必考,史上最通俗大小端字節(jié)序詳解》
《網(wǎng)絡(luò)編程入門從未如此簡單(一):假如你來設(shè)計(jì)網(wǎng)絡(luò),會怎么做?》
《網(wǎng)絡(luò)編程入門從未如此簡單(二):假如你來設(shè)計(jì)TCP協(xié)議,會怎么做?》
>> 更多同類文章 ……
[2] 網(wǎng)絡(luò)編程(高階)資料:
《高性能網(wǎng)絡(luò)編程(一):單臺服務(wù)器并發(fā)TCP連接數(shù)到底可以有多少》
《高性能網(wǎng)絡(luò)編程(二):上一個(gè)10年,著名的C10K并發(fā)連接問題》
《高性能網(wǎng)絡(luò)編程(三):下一個(gè)10年,是時(shí)候考慮C10M并發(fā)問題了》
《高性能網(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í)為什么會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ò)包的接收過程(Linux篇)》
《不為人知的網(wǎng)絡(luò)編程(十一):從底層入手,深度分析TCP連接耗時(shí)的秘密》
《不為人知的網(wǎng)絡(luò)編程(十二):徹底搞懂TCP協(xié)議層的KeepAlive保活機(jī)制》
《IM開發(fā)者的零基礎(chǔ)通信技術(shù)入門(十一):為什么WiFi信號差?一文即懂!》
《IM開發(fā)者的零基礎(chǔ)通信技術(shù)入門(十二):上網(wǎng)卡頓?網(wǎng)絡(luò)掉線?一文即懂!》
《IM開發(fā)者的零基礎(chǔ)通信技術(shù)入門(十三):為什么手機(jī)信號差?一文即懂!》
《IM開發(fā)者的零基礎(chǔ)通信技術(shù)入門(十四):高鐵上無線上網(wǎng)有多難?一文即懂!》
《IM開發(fā)者的零基礎(chǔ)通信技術(shù)入門(十五):理解定位技術(shù),一篇就夠》
>> 更多同類文章 ……
本文已同步發(fā)布于“即時(shí)通訊技術(shù)圈”公眾號。

▲ 本文在公眾號上的鏈接是:點(diǎn)此進(jìn)入。同步發(fā)布鏈接是:http://www.52im.net/thread-3506-1-1.html