1. 程式人生 > >TCP中的三次握手和四次揮手

TCP中的三次握手和四次揮手

TCP中的連線和斷開可以說是在面試中經常被問到的問題之一,正好有空就總結一下,首先回顧一下TCP的相關知識點 ## 1. TCP的基礎知識 ### 1.1 TCP的基本概念 我們知道TCP是運輸層的面向連線的可靠的傳輸協議。**面向連線的**,指的就是在兩個程序傳送資料之前,必須先相互“握手”,確保兩程序可以進行連線。並且這個傳輸是點對點的,即一個TCP連線中只有一個傳送方和接收方;**可靠的**,指的是在任何網路情況下,在TCP傳輸中資料都將完整的傳送到接收方。 ### 1.2 TCP的報文段結構 ![](https://img2020.cnblogs.com/blog/1707576/202008/1707576-20200808160434831-1345139354.jpg) 1. **源埠和目的埠**:和UDP一樣用於多路複用/分解來自或送到上一層 2. **序號**:一個報文段的序號是整個傳送的位元組流序列,而不是該報文段的序列 3. **確認號**:主機正在等待的資料的下一個位元組序號 4. **資料偏移**:指TCP首部的長度,可變。預設長度為20位元組 5. **視窗**:用於流量控制,用於指示接收方願意接受的位元組數量 6. **標誌欄位**: * ACK:當該位為1時,確認號有效 * RST:該位為1時,表示TCP連線中出現異常必須強制斷開連線 * SYC:該位為1時,開始建立連線,並且序號欄位進行序列號初始值的設定 * FIN:該位為1時,斷開連線,通訊雙方相互交換FIN位置為1的TCP段後斷開連線 ## 2. TCP連線 TCP的連線組成包括一臺主機上的快取、變數和與程序連線的套接字,以及另外一臺主機上的快取、變數和與程序連線的套接字。而套接字(socket)由埠號和IP地址組成。 ## 3. TCP連線建立 ![](https://img2020.cnblogs.com/blog/1707576/202008/1707576-20200808160500140-10357448.png) 如圖,開始時,兩個埠都是出於closed狀態,當伺服器埠變成listen時,監聽埠,是否有資料傳來。 1. 第一步:客戶端向服務端傳送一個特殊的TCP報文段。客戶端進入SYN_SENT狀態這個報文段有以下特點: * 不包含應用層資料,封裝在一個IP資料報中傳送給伺服器 * SYN為1(此步是ACK唯一可為0處,其他時間均為1) * 序號段有一個隨機生成的初始序號(client_isn) 2. 第二步:伺服器端收到上步客戶端的報文段後,同時為該TCP連線分配TCP快取和變數,並向該客戶傳送允許連線的報文段。伺服器進入SYN_RCVD狀態,這個報文段特點有: * 不包含應用層資料 * SYN為1,ACK為1 * 確認號段被置為client_isn + 1,序號段被置為server_isn 3. 第三步:客戶端收到上步服務端的報文段後,客戶端為該連線分配快取和變數,同時客戶端向伺服器端傳送報文段,這個報文端特點有: * 可以包含應用層資料 * SYN為0,ACK為1 * 確認號段被置為server_isn + 1 兩端進入ESTABLISHED狀態,連線建立 ## 4. TCP連線斷開 若客戶端決定要關閉該連線(伺服器端也可以發起關閉) ![](https://img2020.cnblogs.com/blog/1707576/202008/1707576-20200808160524442-2049139920.png) 1. 第一次:客戶端傳送帶有FIN被置為1的報文段,進入FIN_WAIT_1狀態,並等待一個來自伺服器的帶有確認的TCP報文段。 2. 第二次:伺服器端收到該報文段後,向客戶端傳送一個確認ACK報文段,進入CLOSE_WAIT狀態。 3. 第三次:伺服器端處理完資料後向客戶端傳送FIN被置為1的報文段,進入LAST_ACK狀態。 4. 第四次:客戶端收到伺服器端的FIN報文段後,向伺服器端傳送一個確認ACK報文段,進入TIME_WAIT狀態,伺服器接收到該ACK報文段後關閉,客戶端在經過2MSL(與具體實現有關,典型值是20s、1分鐘或2分鐘)等待後關閉。 ## 5. 關於TCP連線的面試題 ### 5.1 如何唯一確定一個TCP連線 可以通過四個變數來確定唯一的TCP連線:源地址、源埠、目標地址、目標埠來唯一確定一個TCP連線。其中源地址和目標地址的欄位在IP頭部,作用是通過IP協議傳送報文給哪個主機;源埠和目標埠是在TCP首部,作用是通過TCP協議傳送主機中的哪個程序。 ### 5.2 UDP和TCP有什麼區別 #### 兩者的區別 * UDP面向無連線,利用IP提供無連線的傳輸資料服務 * UDP可以支援一對多、一對一、多對多的互動通訊 * UDP不保證可靠交付資料,傳輸過程中可能會丟包 * UDP首部只有固定的8位元組;TCP首部最短20位元組,能夠變化 #### 應用場景 * UDP用於包總量較少的通訊,如DNS、SNMP;還有視訊、音訊等多媒體通訊,以及廣播通訊等等 * TCP用於需要保證可靠性資料交付的場景,比如FTP、HTTP ### 5.3 為什麼是三次握手? 為什麼TCP連線建立過程中不是兩次或者四次,三次就是最優解了嗎?首先來看看兩次握手建立連線會發生什麼。 ##### 兩次握手 如果連線過程是兩次握手來建立,在理想的網路環境下是可以完成通訊建立的,但是現實的網路環境很複雜,有時候會導致歷史的報文段比新的報文段先到達伺服器端,這時,如果沒有第三次握手,就會造成無法同步序列號情況的發生。舉個例子,客戶端傳送新SYN報文段的序號是100,網路環境中有舊的SYN報文端的序號是80,然而現在舊的先到達伺服器端,那麼伺服器端則會返回一個確認號為81的SYN+ACK報文段,這個時候客戶端接收到的報文段和預期報文段會不一致,就會造成無法同步序列號,達不到TCP可靠運輸的效果,也會浪費資源。那麼如果有第三次握手,這時客戶端會反饋一個RST報文段,終止這次連線,等待新的SYN到來,這樣保證資料的可靠性傳輸。 #### 四次握手 ![](https://img2020.cnblogs.com/blog/1707576/202008/1707576-20200808160717027-862865363.png) 四次握手可以對比四次揮手,客戶端和伺服器端都要分別傳送SYN和ACK報文段,來表示之前的SYN報文已經被成功接收。 然而四次握手可以簡化成三次,第二、三次可以優化成一次。所以三次是保證可靠性傳輸連線的最優解。 ### 5.4 什麼是SYN 泛洪?如何避免 SYN泛洪攻擊通過傳送大量的TCP SYN報文段,而不完成第三次握手的步驟。因為大量的SYN報文段的傳送,伺服器不斷為這些半開連線分配資源,導致伺服器的連線資源被消耗殆盡。 如何避免,現在有一種有效的防禦系統,稱為SYN cookie,它是這樣工作的: * 當伺服器接收到一個SYN報文段時,它並不知道該報文段是來自一個合法使用者還是SYN泛洪攻擊的一部分。因此伺服器不會為該報文段生成一個半開連線。相反,伺服器會生成一個初始TCP序列號cookie值(由目的IP地址與埠號以及僅有該伺服器知道的祕密數的一個複雜函式),併發送給客戶端 * 如果客戶是合法的,將會返回一個ACK報文段。而且當伺服器收到該ACK後,需要驗證該ACK是與前面傳送的SYN相對應,並生成一個具有套接字的全開的連線。如果沒有返回一個ACK報文段,則初始的SYN並沒有對伺服器產生危害,因為伺服器也沒為它分配任何資源。 ### 5.5 為什麼是四次揮手 四次揮手中雙方傳送了FIN報文段,所以在客戶端傳送FIN後,伺服器端接收到後首先會回一個ACK應答報文,因為此時伺服器端可能還有資料沒傳送完,所以在服務端資料處理完後,才傳送FIN報文段給客戶端表示現在可以關閉連線。正是因為這個等待過程,使得比三次握手多一次。 ### 5.6 如果已經建立了連線,客戶端出現故障了怎麼辦? TCP有一個機制是保活機制:定義在一個時間段內,如果沒有任何連線相關的活動,TCP保活機制則開始作用,每隔一個時間間隔會發送一個探測報文,該探測報文包含的資料很少,如果連續幾個探測報文都沒有得到響應,說明該TCP連線已經死亡。 客戶端的故障也分為這幾種: * 對端系統正常回復探測報文,TCP保活時間重置,等待下一個保活時間到來,TCP連線正常執行。 * 對端程式崩潰並重啟,此時可以對探測報完進行響應,但是沒有連線的有效訊息,序列不符合,最後會產生RST報文,這時連線被重置。 * 對端程式徹底崩潰,無法響應探測報,經過幾次連續無響應後TCP會報告此連線已經死亡 ### 5.7 為什麼需要TIME_WAIT狀態 首先要說明,只有主動發起關閉連線的一方才會有TIME_WAIT狀態,那麼為什麼會有TIME_WAIT狀態,這時因為在服務端關閉後,可能還會有其他的資料報未到達客戶端,所以需要再等待一段時間。一般這個時間是2MSL時間,也就是報文段在兩端傳輸的最大往返時間。 TIME_WAIT狀態太多也會導致佔用過多的埠資源,會導致無法建立新的連線 #### 參考部落格: https://mp.weixin.qq.com/s/tH8RFmjrveOmgL