1. HTTP長連接和短連接的定義
- HTTP長連接
- 瀏覽器向服務(wù)器進(jìn)行一次HTTP會話訪問后,并不會直接關(guān)閉這個連接,而是會默認(rèn)保持一段時間,那么下一次瀏覽器繼續(xù)訪問的時候就會再次利用到這個連接。
- 在HTTP/1.1版本中,默認(rèn)的連接都是長連接,我們可以通過Connection: keep-alive字段進(jìn)行指定。
- HTTP短連接
- 瀏覽器向服務(wù)器每進(jìn)行一次HTTP操作都要建立一個新的連接。
- 在HTTP/1.0版本中默認(rèn)是短鏈接
2. HTTP長連接本質(zhì)
HTTP協(xié)議本質(zhì)是OSI七層參考模型中的應(yīng)用層協(xié)議,而網(wǎng)絡(luò)進(jìn)行通信的時候都是通過上層協(xié)議封裝頭部后作為下層協(xié)議的數(shù)據(jù)部分進(jìn)行封裝的,而實際中我們經(jīng)常接觸的是TCP/IP協(xié)議簇,也就是傳輸層利用TCP協(xié)議和網(wǎng)絡(luò)層利用IP協(xié)議。因此HTTP協(xié)議的長連接本質(zhì)上就是TCP的長連接。
2.1 TCP建立連接回顧
上面我們提到了TCP,那么回顧一下,通信雙方在進(jìn)行通信的時候就是要通過“三次握手“來建立連接的,握手的過程大致如圖1所示:
那么通過上圖我們就可以清楚的看到,服務(wù)器和客戶端都建立了一個TCB
傳輸控制塊,這里就是我們進(jìn)行socket
編程的時候管理連接的地方,在這里我們先標(biāo)記這個TCB
,在后續(xù)的文章,我們會詳細(xì)介紹在Linux中TCB
是怎么樣管理連接的。
2.2 TCP釋放連接回顧
在回顧了TCP連接建立之后,我們不妨再來看看TCP四次揮手,如圖2所示:
TCP連接的釋放是看通信雙方誰是主動關(guān)閉的一方,誰是被動關(guān)閉的一方來決定各自狀態(tài)的,具體的內(nèi)容大家依然可以參考《TCP/IP詳解》,這里就不再贅述了。
2.3 TCP長連接
在建立了TCP連接之后,這也就到了這篇文章中比較核心的問題,就是說TCP連接建立之后,并不會在完成一次數(shù)據(jù)通信后就關(guān)閉連接,而是要保持一段時間,那么這個時間是怎么樣保證,又是誰保證的呢?
2.3.1 TCP?;顧C(jī)制
- 為什么要有?;顧C(jī)制?
- 第一點自然是我們這篇文章的主題,通過?;顧C(jī)制,我們可以保證通訊雙方的連接不被釋放掉
- 第二點就是在另一些情況下,如果客戶端或者服務(wù)器發(fā)生了錯誤或者宕機(jī),那么就可以依靠這種?;顧C(jī)制探測出網(wǎng)絡(luò)通信出現(xiàn)了問題,進(jìn)而可以釋放掉這種錯誤連接。
- ?;顧C(jī)制
首先保活機(jī)制的工作原理就是,通過在服務(wù)器端設(shè)置一個?;疃〞r器,當(dāng)定時器開始工作后就定時的向網(wǎng)絡(luò)通信的另一端發(fā)出?;钐綔y的TCP報文,如果接收到了ACK報文,那么就證明對方存活,可以繼續(xù)保有連接;否則就證明網(wǎng)絡(luò)存在故障。
上面只是在原理層面簡單的介紹,根據(jù)文獻(xiàn)[1],我們可以了解到詳細(xì)的內(nèi)容:
如果一個給定的連接在兩個小時之內(nèi)沒有任何動作,則服務(wù)器就向客戶發(fā)送一個探查報文段??蛻糁鳈C(jī)必須處于以下 4個狀態(tài)之一。
狀態(tài)1:客戶主機(jī)依然正常運(yùn)行,并從服務(wù)器可達(dá)??蛻舻腡CP響應(yīng)正常,而服務(wù)器也知道對方是正常工作的。服務(wù)器在兩小時以后將?;疃〞r器復(fù)位。如果在兩個小時定時器到時間之前有應(yīng)用程序的通信量通過此連接,則定時器在交換數(shù)據(jù)后的未來2小時再復(fù)位。
狀態(tài)2:客戶主機(jī)已經(jīng)崩潰,并且關(guān)閉或者正在重新啟動。在任何一種情況下,客戶的TCP都沒有響應(yīng)。服務(wù)器將不能夠收到對探查的響應(yīng),并在75秒后超時。服務(wù)器總共發(fā)送10個這樣的探查,每個間隔75秒。如果服務(wù)器沒有收到一個響應(yīng),它就認(rèn)為客戶主機(jī)已經(jīng)關(guān)閉并終止連接。
狀態(tài)3:客戶主機(jī)崩潰并已經(jīng)重新啟動。這時服務(wù)器將收到一個對其?;钐讲榈捻憫?yīng),但是這個響應(yīng)是一個復(fù)位,使得服務(wù)器終止這個連接。
狀態(tài)4:客戶主機(jī)正常運(yùn)行,但是從服務(wù)器不可達(dá)。這與狀態(tài)2相同,因為TCP不能夠區(qū)分狀態(tài)4與狀態(tài)2之間的區(qū)別,它所能發(fā)現(xiàn)的就是沒有收到探查的響應(yīng)。
- 實際應(yīng)用
那么我們在了解了理論上TCP長連接是通過?;顧C(jī)制來實現(xiàn)的,但是保活機(jī)制并不是RFC規(guī)定的TCP協(xié)議的內(nèi)容,因此有時候在不支持?;顧C(jī)制的機(jī)器上,往往我們也需要先看一下內(nèi)核層面是否支持,如果不支持需要在應(yīng)用層自己去實現(xiàn)這個功能。
在這里我們就來看一下Linux相關(guān)的TCP?;顓?shù)
tcp_keepalive_time,單位:秒,表示發(fā)送的探測報文之前的連接空閑時間,默認(rèn)是7200s。
tcp_keepalive_intvl,單位:秒,表示兩次探測報文之間的間隔時間,默認(rèn)是75s
tcp_keepalive_probes,單位,秒,表示探測的次數(shù),默認(rèn)是9
接下來如果我們需要在應(yīng)用層寫自己的心跳機(jī)制,那么就需要其他方面的一些內(nèi)容了。
2.3.2 TCP長連接和短鏈接比較
- TCP短鏈接
- 優(yōu)點
- 短鏈接不占服務(wù)器的內(nèi)存,服務(wù)器能處理的連接數(shù)量會比較多
- 缺點
- 在有實際的資源要進(jìn)行數(shù)據(jù)通信的時候才建立連接,那么在客戶端發(fā)送完數(shù)據(jù)釋放連接之后當(dāng)服務(wù)器有向客戶端發(fā)送數(shù)據(jù)時就不能做到發(fā)送消息的實時性。
- 頻繁地建立連接、釋放連接會耗費(fèi)大量的CPU和網(wǎng)絡(luò)帶寬資源。
- TCP長連接[2]
- 優(yōu)點
- 通信雙方因為在保活機(jī)制的保證下可以保證數(shù)據(jù)收發(fā)的實時性
- 缺點
- 因為服務(wù)器需要一直保存和客戶端的這條鏈接,因為是有狀態(tài)的,那么在大量并發(fā)連接請求過來時,系統(tǒng)資源可能就不夠了。
- 什么時候需要長連接
- 服務(wù)器需要主動發(fā)送資源給客戶端時
- 客戶端和服務(wù)器通信很頻繁時
- 客戶端宕機(jī)或者掉線時需要服務(wù)器做一些處理時
- TCP長連接設(shè)計時需要考慮的問題
- 默認(rèn)的keep-alive時間比較長,一般的業(yè)務(wù)可能不需要這么久的時間
- socket proxy會讓TCP的保活失效:多有的proxy應(yīng)用只能轉(zhuǎn)發(fā)TCP的應(yīng)用數(shù)據(jù),不能轉(zhuǎn)發(fā)TCP協(xié)議內(nèi)部的包