簡(jiǎn)介
網(wǎng)絡(luò)協(xié)議使不同計(jì)算機(jī)廠家生產(chǎn)的計(jì)算機(jī)在不同類型的操作系統(tǒng)上能夠相互通信,以便在更大的范圍內(nèi)建立計(jì)算機(jī)網(wǎng)絡(luò)。
OSI七層協(xié)議模型
國(guó)際標(biāo)準(zhǔn)化組織(ISO)在1978年提出了“開(kāi)放系統(tǒng)互聯(lián)參考模型”,即著名的OSI/RM模型(Open System Interconnection/Reference Model)。它將計(jì)算機(jī)網(wǎng)絡(luò)體系結(jié)構(gòu)的通信協(xié)議劃分為七層,自下而上依次為:物理層(Physics Layer)、數(shù)據(jù)鏈路層(Data Link Layer)、網(wǎng)絡(luò)層(Network Layer)、傳輸層(Transport Layer)、會(huì)話層(Session Layer)、表示層(Presentation Layer)、應(yīng)用層(Application Layer)。-
TCP/IP四層模型
TCP/IP分層模型(TCP/IP Layening Model)被稱作因特網(wǎng)分層模型(Internet Layering Model)、因特網(wǎng)參考模型(Internet Reference Model),主要分為:應(yīng)用層、運(yùn)輸層、網(wǎng)絡(luò)層、網(wǎng)絡(luò)接口層
1-1 每層所包含協(xié)議 -
五層體系結(jié)構(gòu)
五層體系結(jié)構(gòu)包括:應(yīng)用層、運(yùn)輸層、網(wǎng)絡(luò)層、數(shù)據(jù)鏈路層和物理層。
五層協(xié)議只是OSI和TCP/IP的綜合,實(shí)際應(yīng)用還是TCP/IP的四層結(jié)構(gòu)。為了方便可以把下兩層稱為網(wǎng)絡(luò)接口層。
1-2 協(xié)議模型對(duì)應(yīng)關(guān)系
TCP/IP簡(jiǎn)介
TCP/IP ( Transmission Control Protocol/Internet Protocol )傳輸控制協(xié)
議/因特網(wǎng)互聯(lián)協(xié)議。TCP/IP 是當(dāng)前流行的網(wǎng)絡(luò)傳輸協(xié)議框架,

-
鏈路層:
單個(gè) 0、 l 是沒(méi)有意義的,鏈路層以字節(jié)為單位把 0 與 l 進(jìn)行分組,定義數(shù)據(jù)幀,寫入源和目標(biāo)機(jī)器的物理地址、數(shù)據(jù)、校驗(yàn)位來(lái)傳輸數(shù)據(jù)。
1-4 鏈路層報(bào)文結(jié)構(gòu)
MAC地址長(zhǎng) 6 個(gè)字節(jié)共 48 位,通常使用十六進(jìn)制數(shù)表示。使用ifconfig-a 命令即可看到 MAC 地址。如圖 1-5 所示的 f4:5c:89,即前 24 位由管理機(jī)構(gòu)統(tǒng)一分配,后 24 位由廠商自己分配,保證網(wǎng)卡全球唯一。網(wǎng)卡就像家庭地址一樣,是計(jì)算機(jī)世界范圍內(nèi)的唯一標(biāo)識(shí)。
1-5 MAC地址 - 網(wǎng)絡(luò)層: 根據(jù) IP 定義網(wǎng)絡(luò)地址,區(qū)分網(wǎng)段。子網(wǎng)內(nèi)根據(jù)地址解析協(xié)議(ARP)進(jìn)行 MAC 尋址,子網(wǎng)外進(jìn)行路由轉(zhuǎn)發(fā)數(shù)據(jù)包,這個(gè)數(shù)據(jù)包即IP數(shù)據(jù)包。
- 傳輸層:數(shù)據(jù)包通過(guò)網(wǎng)絡(luò)層發(fā)送到目標(biāo)計(jì)算機(jī)后,應(yīng)用程序在傳輸層定義邏輯端口,確認(rèn)身份后,將數(shù)據(jù)包交給應(yīng)用程序,實(shí)現(xiàn)端口到端口間通信。最典型的傳輸層協(xié)議是UDP和TCP。UDP只是在 IP數(shù)據(jù)包上增加端口等部分信息,是面向無(wú)連接的,是不可靠傳輸,多用于視頻通信、電話會(huì)議等(即
使少一幀數(shù)據(jù)也無(wú)妨)。與之相反,TCP 是面向連接的。所謂面向連接,是一種端到端間通過(guò)失敗重傳機(jī)制建立的可靠數(shù)據(jù)傳輸方式,給人感覺(jué)是有一條固定的通路承載著數(shù)據(jù)的可靠傳輸。 - 應(yīng)用層:傳輸層的數(shù)據(jù)到達(dá)應(yīng)用程序時(shí),以某種統(tǒng)一規(guī)定的協(xié)議格式解讀數(shù)據(jù)。比如 , E-mail 在各個(gè)公司的程序界面、操作、管理方式都不一樣,但是都能夠讀取郵件內(nèi)容,是因?yàn)?SMTP 協(xié)議就像傳統(tǒng)的書信恪式一樣,按規(guī)定填寫郵編及收信人信息。
總結(jié)一下,程序在發(fā)送消息時(shí),應(yīng)用層接既定的協(xié)議打包數(shù)據(jù),隨后由傳輸層加上雙方的端口號(hào),由網(wǎng)絡(luò)層加上雙方的IP地址,由鏈路層加上雙方的MAC地址,并將數(shù)據(jù)拆分成數(shù)據(jù)幀,經(jīng)過(guò)多個(gè)路由器和網(wǎng)關(guān)后,至達(dá)目標(biāo)機(jī)器。簡(jiǎn)而言之,就是按“ 端口→IP地址→MAC地址”這樣的路徑進(jìn)行數(shù)據(jù)的封裝和發(fā)送,解包的時(shí)候反過(guò)來(lái)操作即可。
IP協(xié)議
IP是面向無(wú)連接、無(wú)狀態(tài)的,沒(méi)有額外的機(jī)制保證發(fā)送的包是否有序到達(dá)。IP首先規(guī)定出IP地址格式,該地址相當(dāng)于在邏輯意義上進(jìn)行 了網(wǎng)段的劃分,給每臺(tái)計(jì)算機(jī)額外設(shè)置了一個(gè)唯一的詳細(xì)地址。既然鏈路層可以通過(guò)唯一的MAC地址找到機(jī)器,為什么還需要通過(guò)唯一的IP地址再來(lái)標(biāo)識(shí)呢?簡(jiǎn)單地說(shuō),在世界范圍內(nèi),不可能通過(guò)廣播的方式,從數(shù)以千萬(wàn)計(jì)的計(jì)算機(jī)里找到目標(biāo)MAC地址的計(jì)算機(jī)而不超時(shí)。在數(shù)據(jù)投遞時(shí)就需要對(duì)地址進(jìn)行分層管理。IP地址如圖1-14所示,即30.38.48.22,右邊為物理層發(fā)送和接收數(shù)據(jù)的統(tǒng)計(jì)。

IP地址屬于網(wǎng)絡(luò)層,主要功能在WLAN內(nèi)進(jìn)行路由尋址,選擇最佳路由。IP報(bào)文格式如圖1-7所示,共32位4個(gè)字節(jié),通常用十進(jìn)制數(shù)來(lái)表示。四地址的掩碼0xffffff00表示 255.255.255.0,掩碼相同,則在同一子網(wǎng)內(nèi)。IP協(xié)議在IP報(bào)頭中記錄源IP地址和目標(biāo)IP地址,如圖1-7所示。

協(xié)議結(jié)構(gòu)比較簡(jiǎn)單,重點(diǎn)說(shuō)一下數(shù)據(jù)包的生存時(shí)間,即TTL,它是數(shù)據(jù)包可經(jīng)過(guò)的最多路由器總數(shù)。TTL初始值由源主機(jī)設(shè)置后,數(shù)據(jù)包在傳輸過(guò)程中每經(jīng)過(guò)一個(gè)路由器TTL值則減1,當(dāng)該字段為0時(shí),數(shù)據(jù)包被丟棄,并發(fā)送ICMP報(bào)文通知源主機(jī),以防止源主機(jī)無(wú)休止地發(fā)送報(bào)文。這里擴(kuò)展說(shuō)一下ICMP( Internet Control Message Protocol),它是檢測(cè)傳輸網(wǎng)絡(luò)是否通暢、主機(jī)是否可達(dá)、路由是否可用等網(wǎng)絡(luò)運(yùn)行狀態(tài)的協(xié)議。ICMP雖然并不傳輸用戶數(shù)據(jù),但是對(duì)評(píng)估網(wǎng)絡(luò)健康狀態(tài)非常重要,經(jīng)常使用的ping、tracert命令就是基于ICMP檢測(cè)網(wǎng)絡(luò)狀態(tài)的有力工具。圖1-7中TTL右側(cè)是掛載協(xié)議標(biāo)識(shí),表示IP數(shù)據(jù)包里放置的子數(shù)據(jù)包協(xié)議類型,如6代表TCP、17代表UDP等。
IP報(bào)文在互聯(lián)網(wǎng)上傳輸時(shí),可能要經(jīng)歷多個(gè)物理網(wǎng)絡(luò),才能從源主機(jī)到達(dá)目標(biāo)主機(jī)。比如在手機(jī)上給某個(gè)PC端的朋友發(fā)送一個(gè)信息,經(jīng)過(guò)無(wú)線網(wǎng)的IEEE 802.lx認(rèn)證,轉(zhuǎn)到光纖通信上,然后進(jìn)入內(nèi)部企業(yè)網(wǎng)802.3,并最終到達(dá)目標(biāo)PC。由于不同硬件的物理特性不同,對(duì)數(shù)據(jù)幀的最大長(zhǎng)度都有不同的限制,這個(gè)最大長(zhǎng)度被稱為最大傳輸單元,即MTU(Maximum Transmission Unit)。那么在不同的物理網(wǎng)之間就可能需要對(duì) IP報(bào)文進(jìn)行分片,這個(gè)工作通常由路由器負(fù)責(zé)完成。
IP是TCP/IP的基石,幾乎所有其他協(xié)議都建立在IP所提供的服務(wù)基礎(chǔ)上進(jìn)行傳輸,其中包括在實(shí)際應(yīng)用中用于傳輸穩(wěn)定有序數(shù)據(jù)的TCP。
TCP協(xié)議介紹和建立鏈接
傳輸控制協(xié)議(Transmission Control Protocol, TCP),是一種面向連接、確保數(shù)據(jù)在端到端間可靠傳輸?shù)膮f(xié)議。面向連接是指在發(fā)送數(shù)據(jù)前,需要先建立一條虛擬的鏈路,然后讓數(shù)據(jù)在這條鏈路上“流動(dòng)”完成傳輸。為了確保數(shù)據(jù)的可靠傳輸,不僅需要對(duì)發(fā)出的每一個(gè)字節(jié)進(jìn)行編號(hào)確認(rèn),校驗(yàn)每一個(gè)數(shù)據(jù)包的有效性,在出現(xiàn)超時(shí)情況時(shí)進(jìn)行重傳,還需要通過(guò)實(shí)現(xiàn)滑動(dòng)窗口和擁塞控制等機(jī)制,避免網(wǎng)絡(luò)狀況惡化而最終影響數(shù)據(jù)傳輸?shù)臉O端情形。每個(gè)TCP數(shù)據(jù)包是封裝在IP包中的,每個(gè)IP頭的后面緊接著的是TCP頭,TCP報(bào)文格式如圖1-8所示。

協(xié)議第一行的兩個(gè)端口號(hào)各占兩個(gè)字節(jié),分別表示了源機(jī)器和目標(biāo)機(jī)器的端口號(hào)。這兩個(gè)端口號(hào)與 IP 報(bào)頭中的源 IP 地址和目標(biāo) IP 地址所組成的四元組可唯一標(biāo)識(shí)一條 TCP 連接。由于 TCP 是面向連接的,因此有服務(wù)端和客戶端之分。需要服務(wù)端先在相應(yīng)的端口上進(jìn)行監(jiān)聽(tīng),準(zhǔn)備好接收客戶端發(fā)起的建立連接請(qǐng)求。當(dāng)客戶端發(fā)起第一個(gè)請(qǐng)求建立連接的 TCP 包時(shí),目標(biāo)機(jī)器端口就是服務(wù)端所監(jiān)昕的端口號(hào)。比如一些由國(guó)際組織定義的廣為人知端口號(hào)一一代表 HTTP 服務(wù)的 80 端口、代表 SSH 服務(wù)的22 端口、代表 HTTPS 服務(wù)的 443 端口??赏ㄟ^(guò) netstat 命令列出機(jī)器上已建立的連接信息,其中包含唯標(biāo)識(shí)條連接的四元組,以及各連接的狀態(tài)等內(nèi)容,如圖 1 - 9 所示,圖中的紅框代表端口號(hào)。

協(xié)議第二行和第二行是序列號(hào),各占 4 個(gè)字節(jié)。前者是指所發(fā)送數(shù)據(jù)包中數(shù)據(jù)部分第一個(gè)字節(jié)的序號(hào),后者是指期望收到來(lái)自對(duì)方的下一個(gè)數(shù)據(jù)包中數(shù)據(jù)部分第一個(gè)字節(jié)的序號(hào)。
由于 TCP 報(bào)頭中存在一些擴(kuò)展字段,所以需要通過(guò)長(zhǎng)度為 4 個(gè) bit 的頭部長(zhǎng)度字段表示 TCP 報(bào)頭的大小,這樣接收方才能準(zhǔn)確地計(jì)算出包中數(shù)據(jù)部分的開(kāi)始位置。
TCP的FLAG位由6個(gè)bit組成,分別代表 ACK 、 SYN 、 F町、 URG 、 PSH 、RST,都以置1表示有效。我們重點(diǎn)關(guān)注 SYN, ACK 和 FIN 。SYN(Synchronize Sequence Numbers)用作建立連接時(shí)的同步信號(hào);ACK ( Acknowledgement)用于對(duì)收到的數(shù)據(jù)進(jìn)行確認(rèn),所確認(rèn)的數(shù)據(jù)由確認(rèn)序列號(hào)表示; FIN ( Finish)表示后面有數(shù)據(jù)需要發(fā)送,通常意味著所建立的連接需要關(guān)閉了。TCP 報(bào)頭申的其他字段可以閱讀RC793 來(lái)掌握。
接下來(lái)重點(diǎn)分析 TCP 中連接建立的原理。圖1-10展示了正常情況下通過(guò)三次握手建立連接的過(guò)程。三次握手指的是建立連接的三個(gè)步驟:
- A機(jī)器發(fā)出一個(gè)數(shù)據(jù)包并將SYN置1,表示希望建立連接。這個(gè)包中的序列號(hào)假設(shè)是 x。
- B機(jī)器收到A機(jī)器發(fā)過(guò)來(lái)的數(shù)據(jù)包后,通過(guò)SYN得知這是一個(gè)建立連接的請(qǐng)求,于是發(fā)送一個(gè)響應(yīng)包并將SYN和ACK標(biāo)記都置1。假設(shè)這個(gè)包中的序列號(hào)是y,而確認(rèn)序列號(hào)必須是x+1,表示收到了A發(fā)過(guò)來(lái)的SYN。在TCP中,SYN被當(dāng)作數(shù)據(jù)部分的一個(gè)字節(jié)。
-
A收到B的響應(yīng)包后需進(jìn)行確認(rèn),確認(rèn)包中將ACK置1,并將確認(rèn)序列號(hào)設(shè)置為y+1,表示收到了來(lái)自B的SYN。
1-10
這里為什么需要第3次握手?它有兩個(gè)主要目的:信息對(duì)等和防止超時(shí)。先從信息對(duì)等角度來(lái)看,如表1-11所示,雙方只有確定4類信息,才能建立連接。在第2次握手后,從B機(jī)器視角看還有兩個(gè)紅色的NO信息無(wú)法確認(rèn)。在第3次握手后, B機(jī)器才能確認(rèn)自己的發(fā)報(bào)能力和對(duì)方的收?qǐng)?bào)能力是正常的。
1-11 三次握手確認(rèn)的信息
連接三次握手也是防止出現(xiàn)請(qǐng)求超時(shí)導(dǎo)致臟連接。TTL網(wǎng)絡(luò)報(bào)文的生存時(shí)間往往都會(huì)超過(guò)TCP請(qǐng)求超時(shí)時(shí)間,如果兩次握手就可以創(chuàng)建連接,傳輸數(shù)據(jù)并釋放連接后,第一個(gè)超時(shí)的連接請(qǐng)求才到達(dá)B機(jī)器的話,B機(jī)器會(huì)以為是A創(chuàng)建新連接的請(qǐng)求,然后確認(rèn)同意創(chuàng)建連接。因?yàn)锳機(jī)器的狀態(tài)不是 SYN_SENT,所以直接丟棄了B的確認(rèn)數(shù)據(jù),以致最后只是B機(jī)器單方面創(chuàng)建連接完畢,簡(jiǎn)要示意圖如圖1-12所示。
1-12 兩次握手導(dǎo)致的TCP臟鏈接
如果是三次握手,則B機(jī)器收到連接請(qǐng)求后,同樣會(huì)向A機(jī)器確認(rèn)同意創(chuàng)建連接,但因?yàn)锳機(jī)器不是SYN_SENT狀態(tài),所以會(huì)直接丟棄,B機(jī)器由于長(zhǎng)時(shí)間沒(méi)有收到確認(rèn)信息,最終超時(shí)導(dǎo)致連接創(chuàng)建失敗,因而不會(huì)出現(xiàn)臟連接。根據(jù)抓包分析,呈現(xiàn)出三次握手請(qǐng)求過(guò)程,SYN+ACK的應(yīng)答,告訴A機(jī)器期望下一個(gè)數(shù)據(jù)包的第一個(gè)字節(jié)序號(hào)為1,如圖1-13所示。
1-13 TCP三次握手抓包分析
從編程的角度,TCP連接的建立是通過(guò)文件描述符(File Descriptor,fd)完成的。通過(guò)創(chuàng)建套接字獲得一個(gè)fd,然后服務(wù)端和客戶端需要基于所獲得的fd調(diào)用不同的函數(shù)分別進(jìn)入監(jiān)聽(tīng)狀態(tài)和發(fā)起連接請(qǐng)求。由于fd的數(shù)量將決定服務(wù)端進(jìn)程所能建立連接的數(shù)量,對(duì)于大規(guī)模分布式服務(wù)來(lái)說(shuō),當(dāng)fd不足時(shí)就會(huì)出現(xiàn)“open too many files”錯(cuò)誤而使得無(wú)法建立更多的連接。為此,需要注意調(diào)整服務(wù)端進(jìn)程和操作系統(tǒng)所支持的最大文件句柄數(shù)。通過(guò)使用ulimit -n命令來(lái)查看單個(gè)進(jìn)程可以打開(kāi)文件句柄的數(shù)量。如果想查看當(dāng)前系統(tǒng)各個(gè)進(jìn)程產(chǎn)生了多少句柄,可以使用如下的命令:
lsof -n awk '{print $2}'|sort|uniq -c |sort -nr|more
執(zhí)行結(jié)果如圖1-14所示,左側(cè)列是句柄數(shù),右側(cè)列是進(jìn)程號(hào)。lsof命令用于查看當(dāng)前系統(tǒng)所打開(kāi)fd的數(shù)量。在Linux系統(tǒng)中,很多資源都是以fd的形式進(jìn)行讀寫的,除了提到的文件和TCP連接,UDP數(shù)據(jù)報(bào)、輸入輸出設(shè)備等都被抽象成了fd。

想知道具體的PID對(duì)應(yīng)的具體應(yīng)用程序是誰(shuí),使用如下命令即可:
ps -ax|grep 32764
TCP在協(xié)議層面支持Keep Alive功能,即隔段時(shí)間通過(guò)向?qū)Ψ桨l(fā)送數(shù)據(jù)表示連接處于健康狀態(tài)。不少服務(wù)將確保連接健康的行為放到了應(yīng)用層,通過(guò)定期發(fā)送心跳包檢查連接的健康度。一旦心跳包出現(xiàn)異常不僅會(huì)主動(dòng)關(guān)閉連接,還會(huì)回收與連接相關(guān)的其他用于提供服務(wù)的資源,確保系統(tǒng)資源最大限度地被有效利用。
TCP斷開(kāi)連接
TCP是全雙工通信,雙方都能作為數(shù)據(jù)的發(fā)送方和接收方,但TCP連接也會(huì)有斷開(kāi)的時(shí)候。所謂相愛(ài)容易分手難,建立連接只有三次,而揮手?jǐn)嚅_(kāi)則需要四次,如圖1-15所示。A機(jī)器想要關(guān)閉連接,則待本方數(shù)據(jù)發(fā)送完畢后,傳遞FIN信號(hào)給B機(jī)器。B機(jī)器應(yīng)答ACK,告訴A機(jī)器可以斷開(kāi),但是需要等B機(jī)器處理完數(shù)據(jù),再主動(dòng)給A機(jī)器發(fā)送FIN信號(hào)。這時(shí),A機(jī)器處于半關(guān)閉狀態(tài)(FIN_WAIT_2),無(wú)法再發(fā)送新的數(shù)據(jù)。B機(jī)器做好連接關(guān)閉前的準(zhǔn)備工作后,發(fā)送FIN給A機(jī)器,此時(shí)B機(jī)器也進(jìn)入半關(guān)閉狀態(tài)(CLOSE_WAIT)。A機(jī)器發(fā)送針對(duì)B機(jī)器FIN的ACK后,進(jìn)入TIME-WAIT狀態(tài),經(jīng)過(guò)2MSL(Maximum Segment Lifetime)后,沒(méi)有收到B機(jī)器傳來(lái)的報(bào)文,則確定B機(jī)器已經(jīng)收到A機(jī)器最后發(fā)送的ACK指令,此時(shí)TCP連接正式釋放。具體釋放步驟如圖1-15所示。

通過(guò)抓包分析,如圖1-16所示紅色箭頭表示B機(jī)器已經(jīng)清理好現(xiàn)場(chǎng),并發(fā)送FIN+ACK。注意,B機(jī)器主動(dòng)發(fā)送的兩次ACK應(yīng)答的都是81,第一次進(jìn)入CLOSE_WAIT狀態(tài),第二次應(yīng)答進(jìn)入LAST_ACK狀態(tài),表示可以斷開(kāi)連接,在綠色箭頭處,A機(jī)器應(yīng)答的就是Seq=81。

四次揮手?jǐn)嚅_(kāi)連接用通俗的說(shuō)法可以形象化地這樣描述。
男生:我們分手吧。
女生:好的,我的東西收拾完,發(fā)信息給你。(此時(shí)男生不能再擁抱女生了。)(1個(gè)小時(shí)后)
女生:我收拾好了,分手吧。(此時(shí),女生也不能再擁抱男生了。)
男生:好的。(此時(shí),雙方約定經(jīng)過(guò)2個(gè)月的過(guò)渡期,雙方才可以分別找新的對(duì)象。)
圖1-15中的紅色字體所示的TIME_WAIT和CLOSE_WAIT分別表示主動(dòng)關(guān)閉和被動(dòng)關(guān)閉產(chǎn)生的階段性狀態(tài),如果在線上服務(wù)器大量出現(xiàn)這兩種狀態(tài),就會(huì)加重機(jī)器負(fù)載,也會(huì)影響有效連接的創(chuàng)建,因此需要進(jìn)行有針對(duì)性的調(diào)優(yōu)處理。
- TIME_WAIT:主動(dòng)要求關(guān)閉的機(jī)器表示收到了對(duì)方的FIN報(bào)文,并發(fā)送出了ACK報(bào)文,進(jìn)入TIME_WAIT狀態(tài),等2MSL后即可進(jìn)入到CLOSED狀態(tài)。如果FIN_WAIT_1狀態(tài)下,同時(shí)收到帶FIN標(biāo)志和ACK標(biāo)志的報(bào)文時(shí),可以直接進(jìn)入TIME_WAIT狀態(tài),而無(wú)須經(jīng)過(guò)FIN_WAIT_2狀態(tài)。
- CLOSE_WAIT:被動(dòng)要求關(guān)閉的機(jī)器收到對(duì)方請(qǐng)求關(guān)閉連接的FIN報(bào)文,在第一次ACK應(yīng)答后,馬上進(jìn)入CLOSE_WAIT狀態(tài)。這種狀態(tài)其實(shí)表示在等待關(guān)閉,并且通知應(yīng)用程序發(fā)送剩余數(shù)據(jù),處理現(xiàn)場(chǎng)信息,關(guān)閉相關(guān)資源。
在TIME_WAIT等待的2MSL是報(bào)文在網(wǎng)絡(luò)上生存的最長(zhǎng)時(shí)間,超過(guò)閥值便將報(bào)文丟棄。一般來(lái)說(shuō),MSL大于TTL衰減至0的時(shí)間。在RFC793中規(guī)定MSL為2分鐘。但是在當(dāng)前的高速網(wǎng)絡(luò)中,2分鐘的等待時(shí)間會(huì)造成資源的極大浪費(fèi),在高并發(fā)服務(wù)器上通常會(huì)使用更小的值。既然TIME_WAIT貌似是百害而無(wú) 一利的,為何不直接關(guān)閉,進(jìn)入 CLOSED狀態(tài)呢?原因有如下幾點(diǎn)。
第一,確認(rèn)被動(dòng)關(guān)閉方能夠順利進(jìn)入CLOSED狀態(tài)。如圖1-15所示,假如最后一個(gè)ACK由于網(wǎng)絡(luò)原因?qū)е聼o(wú)法到達(dá)B機(jī)器,處于LAST_ACK的B機(jī)器通?!白孕拧钡匾詾閷?duì)方?jīng)]有收到自己的FIN+ACK報(bào)文,所以會(huì)重發(fā)。A機(jī)器收到第二次的FIN+ACK報(bào)文,會(huì)重發(fā)一次ACK,并且重新計(jì)時(shí)。如果A機(jī)器收到B機(jī)器的FIN+ACK報(bào)文后,發(fā)送一個(gè)ACK給B機(jī)器,就“自私”地立馬進(jìn)入CLOSED狀態(tài),可能會(huì)導(dǎo)致B機(jī)器無(wú)法確保收到最后的ACK指令,也無(wú)法進(jìn)入CLOSED狀態(tài)。這是A機(jī)器不負(fù)責(zé)任的表現(xiàn)。
第二,防止失效請(qǐng)求。這樣做是為了防止己失效連接的請(qǐng)求數(shù)據(jù)包與正常連接的請(qǐng)求數(shù)據(jù)包混淆而發(fā)生異常。
因?yàn)門IME_WAIT狀態(tài)無(wú)法真正釋放句柄資源,在此期間,Socket中使用的本地端口在默認(rèn)情況下不能再被使用。該限制對(duì)于客戶端機(jī)器來(lái)說(shuō)是無(wú)所謂的,但對(duì)于高并發(fā)服務(wù)器來(lái)說(shuō),會(huì)極大地限制有效連接的創(chuàng)建數(shù)量,成為性能瓶頸。所以,建議將高并發(fā)服務(wù)器TIME_WAIT超時(shí)時(shí)間調(diào)小。
在服務(wù)器上通過(guò)變更/etc/sysctl.conf文件來(lái)修改該省略值(秒):net.ipv4.tcp_fin_timeout=30(建議小于30秒為宜)。
netstat -n I awk '/^tcp/ {++S[$NF]} END (for(a in S) print a, S[a]}'
查看各連接狀態(tài)的計(jì)數(shù)情況,為了使數(shù)據(jù)快速生效,2MSL從240秒更改為5秒。參數(shù)生效后如圖1-17所示,TIME_WAIT很快從75個(gè)降為1個(gè)。

在sysctl.conf中還有其他連接參數(shù)也用來(lái)不斷地調(diào)優(yōu)服務(wù)器TCP連接能力,以提升服務(wù)器的有效利用率。畢竟現(xiàn)代網(wǎng)絡(luò)和路由處理能力越來(lái)越強(qiáng),跨國(guó)時(shí)延通常也在1秒鐘以內(nèi),丟包率極低。如何快速地使連接資源被釋放和復(fù)用,參數(shù)的優(yōu)化往往可以取得事半功倍的效果。記得某大公司在大型購(gòu)物節(jié)時(shí),系統(tǒng)宕機(jī),老總下令要加一倍服務(wù)器來(lái)解決問(wèn)題。事實(shí)上,如果是參數(shù)配置錯(cuò)誤導(dǎo)致的系統(tǒng)宕機(jī),即使增加硬件資源,也無(wú)法達(dá)到好的效果。硬件的增加與性能的提升絕對(duì)不是線性相關(guān)的,更多的時(shí)候是對(duì)數(shù)曲線關(guān)系。
TIME_WAIT是揮手四次斷開(kāi)連接的尾聲,如果此狀態(tài)連接過(guò)多,則可以通過(guò)優(yōu)化服務(wù)器參數(shù)得到解決。如果不是對(duì)方連接的異常,一般不會(huì)出現(xiàn)連接無(wú)法關(guān)閉的情況。但是CLOSE_WAIT過(guò)多很可能是程序自身的問(wèn)題,比如在對(duì)方關(guān)閉連接后,程序沒(méi)有檢測(cè)到,或者忘記自己關(guān)閉連接。在某次故障中,外部請(qǐng)求出現(xiàn)超時(shí)的情況,當(dāng)時(shí)的 Apache服務(wù)器使用的是默認(rèn)的配置方式,通過(guò)命令
netstat -ant|grep -i "443"lgrep CLOSE_WAIT|wc -l
發(fā)現(xiàn)在HTTPS的443端口上堆積了2.1萬(wàn)個(gè)左右的CLOSE_WAIT狀態(tài)。經(jīng)排查發(fā)現(xiàn),原來(lái)是某程序處理完業(yè)務(wù)邏輯之后沒(méi)有釋放流操作,但程序一直運(yùn)行正常,直到運(yùn)營(yíng)活動(dòng)時(shí)才大量觸發(fā)該業(yè)務(wù)邏輯,最終導(dǎo)致故障的產(chǎn)生。
文章中的知識(shí)來(lái)自《碼出高效Java 開(kāi)發(fā)手冊(cè)》







