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


TCP中的連接和斷開可以說是在面試中經常被問到的問題之一,正好有空就總結一下,首先回顧一下TCP的相關知識點

1. TCP的基礎知識

1.1 TCP的基本概念

我們知道TCP是運輸層的面向連接的可靠的傳輸協議。面向連接的,指的就是在兩個進程發送數據之前,必須先相互“握手”,確保兩進程可以進行連接。並且這個傳輸是點對點的,即一個TCP連接中只有一個發送方和接收方;可靠的,指的是在任何網絡情況下,在TCP傳輸中數據都將完整的發送到接收方。

1.2 TCP的報文段結構

  1. 源端口和目的端口:和UDP一樣用於多路復用/分解來自或送到上一層

  2. 序號:一個報文段的序號是整個傳送的字節流序列,而不是該報文段的序列

  3. 確認號:主機正在等待的數據的下一個字節序號

  4. 數據偏移:指TCP首部的長度,可變。默認長度為20字節

  5. 窗口:用於流量控制,用於指示接收方願意接受的字節數量

  6. 標志字段

    • ACK:當該位為1時,確認號有效
    • RST:該位為1時,表示TCP連接中出現異常必須強制斷開連接
    • SYC:該位為1時,開始建立連接,並且序號字段進行序列號初始值的設定
    • FIN:該位為1時,斷開連接,通信雙方相互交換FIN位置為1的TCP段后斷開連接

2. TCP連接

2.1 什么是連接(connection)和會話(Session)

連接是數據傳輸雙方的契約,在設計上,連接是一種傳輸數據的行為,具體來說,數據收發雙方的內存中都建立一個用於維護數據傳輸狀態的對象,比如TCP 的連接組成包括一台主機上的緩存、變量和與進程連接的套接字,以及另外一台主機上的緩存、變量和與進程連接的套接字。(由端口號和IP地址組成)所以連接是網絡行為狀態的記錄

會話是應用的行為,比如說你在微信上給人發消息,打開應用聊天窗口和對方聊天是一個會話,但是連接只有在進行發消息、語音的時候連接才開啟。其他不發消息和語音時,連接可能暫時斷開,但是只要不關聊天窗口,會話時一直存在的。

總結而言,會話是應用層的概念,連接是傳輸層的概念,正是因為如此,在 TCP 連接的時候需要握手建立連接。

3. TCP連接建立

3.1 TCP 協議中的基本操作

也就是報文段的標志字段的含義和功能:

  • SYN(Synchronization):請求同步,一個 Host 主動向另外一個 Host 發起連接。當 SYN=1,ACK=0 時,表示這是一個請求建立連接的報文段;當 SYN=1,ACK=1 時,表示對方同意建立連接
  • PSH(Push): 數據推送,一個 Host 主動向另外一個 Host 發送數據
  • FIN(Finish): 請求完成,一個 Host 主動斷開請求,如果 FIN=1,表示數據已經發送完成,可以釋放連接。
  • ACK:表示前面的確認號字段是否有效。ACK=1 時表示有效。只有當 ACK=1 時,前面的確認號字段才有效。TCP 規定,連接建立后,ACK 必須為 1
  • RST:表示是否重置連接。如果 RST=1,說明 TCP 連接出現了嚴重錯誤(如主機崩潰),必須釋放連接,然后再重新建立連接。

如圖,開始時,兩個端口都是出於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連接斷開

若客戶端決定要關閉該連接(服務器端也可以發起關閉)

  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到來,這樣保證數據的可靠性傳輸。

四次握手

四次握手可以對比四次揮手,客戶端和服務器端都要分別發送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/tH8RFmjrveOmgLvk9hmrkw


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM