TCP協議學習總結(上)

在計算機領域,數據的本質無非0和1,創造0和1的當然偉大,但真正百花齊放的仍是基於0和1之上的各類層次之間的組合(數據結構)所帶給咱們人類各類各樣的可能性。例如TCP協議,咱們的生活無不無時無刻的站在TCP協議這個「巨人」的肩膀上,最簡單的一個打開手機的動做。因此對TCP的認識和理解,可謂愈來愈常識化。算法

TCP/IP五層協議服務器

 雖然TCP是一種計算機網絡協議,但本質仍是人與人之間的一種約定,只不過由計算機去執行而已,把協議的細節與做用解耦,讓咱們人類只需專一於基於它的應用呈現之上便可。協議即「規則」,若是咱們把光纖「橫斜面」剖析,咱們看到的就是數據的本質0和1,以下圖所示:網絡

0和1是點對點之間通訊的信息「載體」,咱們須要有一個規則去翻譯這些「載體」,比如如小白和小黑之間的「敲聲傳話遊戲」的約定,他們能夠約定「敲一下」表明「是」,「敲兩下」表明「不是」等。這些「敲聲」跟光纖上的「0」和「1」都是承載着同樣的任務——信息載體。數據結構

 從整個網絡層次來看,TCP/IP協議體系是網絡的一個核心協議組,有一點須要知道的是TCP/IP協議體系並不是只有TCP協議和IP協議,而是包含了物理層、鏈路層、網絡層、運輸層、應用層,而每一層次又有不一樣的協議,例如運輸層協議除了TCP協議還有UDP協議。固然這裏我只是爲了接下來學習TCP協議的一個宏觀認識。從上圖能夠看出,從0和1的基本信息單元到TCP協議的數據結構還要通過鏈路層和網絡層的層層分解,換句話說,也就是TCP協議的數據以「段」單元,封裝在網絡層的IP協議上,IP協議的數據是以「數據報」爲單元,它一樣封裝在鏈路層的以太網標準協議裏面。本文的重點在TCP協議的學習,瞭解了TCP的原理,其餘協議的數據結構和邏輯大同小異了。併發

 TCP的首部高併發

 

從「TCP/IP五層協議體系圖」能夠看出,每個協議都會有個「頭部」,TCP也不例外,其實這個「頭部」就是該協議的數據結構以及規則的說明,但不管協議的玩法如何變化,它仍是離不開0和1的信息載體。學習

源端口號:咱們都知道IP是跟主機相關,而每臺主機又能夠有不一樣的應用進程在運行,因此端口更多能夠指運行在主機上的應用進程,因此源端口號也就是基於TCP協議傳輸數據的「發送方」。spa

目的端口:就是等待TCP協議發送方數據的「接收方」,其實所謂的端口也就是應用進程與應用進程之間通訊的監聽出入口。計算機網絡

序列號:這個數字是用來表示通訊雙方「單向」數據量流動數量表示,上面所介紹的0和1是最小的數據傳輸單元,咱們稱爲「比特(bit)」。而這個序列號記錄的是以「字節」爲單位的計數器(1字節=8比特)。例如A要傳輸給B的512字節數據,假設初始序列號爲1024(注意:每次初始化序號都會不同,TCP有一個比較複雜的初始化算法),那麼他們傳輸過程的序列號爲1536。這個序列號會隨着雙方「交流」而不斷的增長,由於序列號一共32比特,因此最大值也就是2^32-1,到達最大值後從新從0開始。由於TCP是一個可靠的協議,序列號的存在是其可靠的關鍵因素之一。翻譯

 

確認序列號:既然每一個傳輸的字節都被計數,確認序列號包含發送確認的一端所指望收到下一個序號。所以,確認序列號應當是上次已成功接收到數據字節序列號加1。只有ACK標識(下面會介紹)爲1時確認序列號才生效。由於TCP爲應用層提供雙工服務,意味着數據能在兩個方向上獨立地進行傳輸,所以鏈接的每一端(客戶端和服務端)必須保持每一個方向上的傳輸序列號。例如A傳送給B的序列號爲1024(A維護),但B傳送給A的有本身的序列號須要維護(B維護)。

首部長度:TCP首部的「選項」不啓用,那麼TCP的頭部就是20字節,但由於存在「選項」的部分,因此頭部可能存在大於20字節的可能性。由於「首部長度標識」有4位,因此最大值爲2^4-1=15,而這個標識維護頭部的長度是以32比特爲單元,因此頭部最大長度爲15*32比特(4字節)=60字節。

標誌:每一個標誌佔1比特,它們中的多個可同時被設置爲1,每一個標誌的用法以下:

URG:緊急指針(urgent pointer)有效;

ACK:確認序號有效;

PSH:接收方應該儘快將這個報文段交給應用層;

RST:重建鏈接;

SYN:同步序號用來發起一個鏈接;

FIN:發送端完成發送任務;

窗口大小:TCP的流量控制由鏈接的每一端經過聲明的窗口大小來提供(以字節爲單位),窗口大小是一個16比特字段,於是窗口最大爲65535字節。換個說法,窗口比如如「緩衝區」,TCP是一個雙工單向傳送的通訊協議,雙方都須要有本身的窗口(緩衝區)大小相互告知,若是接收到的應用處理速度慢(從緩衝區消費數據慢),那麼它的窗口很容易就滿了,發送方就會中止發送,等到接受方的窗口有「空餘」了才繼續發送。

檢驗和:檢驗和(類數據簽名)覆蓋了整個的TCP報文段:TCP首部和TCP數據,由於TCP是一個可靠的協議,因此這是強制性的字段,由發送方計算和設置,並由接收方進行驗證,這就是可靠性保證的重要手段。

緊急指針:只有當URG標誌置1時緊急指針纔有效。緊急指針是一個正的偏移量,和序號字段中的值相加表示緊急數據最後一個報文段。

選項:就是TCP頭部的不是「必須」的選項,例如常見的可選字段是「最長報文大小」,又稱爲MSS(Maximun Segment Size),每一個鏈接方一般都在通訊的第一個報文段中指明這個選項。

數據:整個TCP報文段是又報文頭部和報文數據組成的,除去了頭部就是數據,但數據是可空的,例如建立鏈接(SYN)和結束傳輸(FIN)的TCP報文都是沒有數據的。

 TCP鏈接的創建和終止

 

TCP創建鏈接須要三次握手,分別以下:

1)、客戶端(請求方)發送一個SYN段指明客戶打算鏈接的服務器端口,以及把初始化序號x附上,這就是大名鼎鼎的SYN報文段,在介紹頭部的時候已經提過,SYN報文段是沒有數據的,由於鏈接都沒正式鏈接,發送數據沒意義。但也提到了客戶端會附上它的最大報文段,也就是告訴接收方它最大的一個報文段能接受多少數據。

2)、服務端(處於監聽狀態)收到SYN請求後發回包含服務端的初始序號的SYN報文段做爲應答(上文提到過客戶端和服務端的初始序號都是各自維護的)。同時,將確認序號設置爲客戶的ISN加1(由於SYN將佔用一個序號),以對客戶的SYN報文段進行確認。在服務端想客戶端響應SYN的時候一樣可能會附上它接收的最大報文段,但記住,畢竟最大報文段是可選的,不必定會存在,不相互告知的話就會使用默認值。

3)、客戶端必須將確認序號設置爲服務器的ISN加1一對服務器的SYN報文段進行確認。

當以上三個報文段完成交互後就證實鏈接已經創建,這個過程也成爲「三次握手」。接下來客戶端就能夠發送數據給服務端,服務端能夠響應數據。其實不少時候,客戶端在第三個報文段(也就是第三次握手)的時候就已經附帶數據了。由於它已經不須要等待對方第四次握手的交互確認。正常鏈接的第四個報文段也是客戶端發送數據的報文段,因此既然第三次和第四次都是客戶端,爲了省了一個交互,客戶端能夠直接從第三個報文段(應答服務端ack)附上數據。

創建一個鏈接須要三次握手,而終止一個鏈接須要通過4次握手,這是因爲TCP的半關閉(half close)形成的。既然一個TCP鏈接是全雙工的(即數據在兩個方向上能同時傳遞),所以每一個方向必須單獨地進行關閉。當一端收到一個FIN,它必須通知應用層另外一端已經終止了那個方向的數據傳送。發送FIN一般是應用層進行關閉的結果。比較常見的仍是客戶端關閉,但服務端也能夠設置主動關閉,例如Nginx相關策略配置。

TCP終止鏈接須要四次握手,分別以下:

1)、首先關閉的一方(即發送第一個FIN)將執行主動關閉,上圖顯示主動關閉的一方是客戶端。

2)、當服務端收到這個FIN報文段時,它將發回一個ACK,確認序號爲收到的序號加1,就像上圖的ack=u+1,由於FIN跟SYN同樣也佔用一個序號。

3)、服務端把收到的FIN的消息告訴應用程序(傳送一個文件結束符),接着這個應用程序就會關閉它的鏈接(以上提過,創建和關閉都是由應用主動發起的),致使服務端的TCP端發送一個FIN給客戶端。須要注意的是,畢竟TCP是雙工的,客戶端關閉鏈接不表明服務端就能夠馬上關閉,若是客戶端發起關閉的時候,服務端尚未響應完數據給客戶端,服務端仍是須要把數據發完了再去關閉的,而客戶端主動發起了閉關也不會馬上罷工,它仍是會進入「FIN_WAIT2」狀態進行數據接收,直到服務端發送完了並最後發送結束鏈接報文段(FIN),才進入TIME_WAIT狀態。

4)、客戶端收到服務端的FIN報文段時,它會馬上對此FIN進行ACK回覆,服務端收到後就直接進入關閉狀態(CLOSED)。

由於TCP是全雙工的,雙方都各類維護本身單向傳送數據的鏈接,因此必然會存在雙方同時主動關閉的狀況,以下圖所示:

當雙方同時向對方發送FIN執行主動鏈接時,雙方均從ESTABLISHED狀態變爲FIN_WAIT_1狀態。雙方都收到FIN後,狀態由FIN_WAIT_1變遷至CLOSING,併發送最後的ACK。當收到ACK時,雙方的狀態變爲TIME_WAIT。

TCP的狀態遷變

 經過以上創建和終止鏈接能夠看到,不管客戶端仍是服務端,不管是鏈接方仍是結束方都存在許多「狀態」,每一個狀態隨着各類條件不斷變化,具體狀態的遷變能夠經過下圖來進行總結。

2MSL等待狀態

 從上圖遷變狀態能夠看到,TCP主動關閉的一方都會進入TIME_WAIT狀態,也稱爲2MSL(最大報文段生存時間)等待狀態。之因此要等待,是由於關閉方要確認處於「CLOSE_WAIT」狀態的被關閉方收到它最後的ACK報文,報文的在網絡上單向傳送的最大時間叫作MSL,那麼等待確認報文來回的時間就是2MSL,若是被關閉方在2MSL內都沒有收到ACK,它會繼續發送FIN報文,而若是關閉方在2MSL內沒有收到對方的報文就默認對方已經收到。

報文在網絡上的生存時間並不僅有TCP決定的,在網絡層的IP協議對數據報一樣存在着網絡單向傳送的時間限制,這個限制的約定叫TTL(Time To Live)。TTL的時間單位並不是時間單位,而是「跳數」,數據包每通過一個路由就叫「一跳」,不一樣系統對IP數據包的跳數初始值都不同,例若有些Linux默認值是255。每通過一個路由,總生命跳數就減1,直到爲0都尚未到達目的地就丟棄。255跳究竟是多少秒呢?其實這都是一個不肯定數字。若是一個數據包通過255個路由都還沒到達目的地,我想目的地多是「火星」。並TCP是「坐」在IP協議之上的,因此TCP的MSL確定不能比TTL短,RFC793[Postel 1981c]指出MSL爲2分鐘。然而,實現中的經常使用值是30秒,1分鐘或2分鐘。要知道,0和1在光纖上傳送的速度是「光速(約300000km/s)」,30秒的時間跑了不知道多少趟地球了,因此正常狀況下都會大於TTL了(除非部分路由十分磨蹭)。若是作過一些高併發系統的同窗,多少會遇到一些諸如time_wait過多的現象,例如WEB服務器配置主動關閉鏈接策略或鏈接有效時間短而主動關閉,大量的time_wait會佔用文件描述符,而很容易致使耗光系統默認的1024個最大文件打開數(fs.file-max)而沒法正常服務。

同時打開和同時關閉

 有時候TCP創建鏈接不必定必須是三次握手,有時可能會是4次。沒錯,當雙發同時進行請求主動打開鏈接的時候就是4次,以下圖所示。這個時候,並無誰是客戶端誰是服務端之稱,由於雙方都有主動發送數據的權利。這種狀況應該不多見,若是須要模擬仍是能夠的,把雙方的網速經過某些手段把它下降,那麼就有可能演示。

學習總結

 本次總結更可能是對TCP協議的一個基礎瞭解,包括TCP創建鏈接的正常三次握手和十分罕見的同步創建鏈接的4次握手,以及關閉鏈接的正常4次握手和同步關閉鏈接致使雙方都進入TIME_WAIT狀態的4次握手。最後整體學習了TCP客戶端以及服務端各類狀態遷變的概要圖,十分清晰地對TCP各類概況的描述,以及爲何會有TIME_WAIT和2MSL的概念。

相關文章
相關標籤/搜索