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