【學習總結】TCP協議理解

NO IMAGE

TCP

1. TCP概念相關

[!NOTE]
TCP(Transmission Control Protocol),又叫傳輸控制協議。
TCP協議是面向連接的,可靠的,基於字節流的傳輸協議。在基於 TCP 進行通信時,通信雙方需要先建立一個 TCP 連接,建立連接需要經過三次握手,斷開連接的時候需要經過四次揮手。

1.1 TCP頭部

【學習總結】TCP協議理解

對於 TCP 頭部來說,以下幾個字段是很重要的:

  • 序列號 (Sequence number),這個序號保證了 TCP 傳輸的報文都是有序的,對端可以通過序號順序的拼接報文

  • 確認號 (Acknowledgement Number),這個序號表示數據接收端期望接收的下一個字節的編號是多少,同時也表示上一個序號的數據已經收到

  • 窗口大小 (Window Size),表示還能接收多少字節的數據,用於流量控制

  • 標識符

    • ACK=1 :該字段為一表示確認號字段有效。此外,TCP 還規定在連接建立後傳送的所有報文段都必須把 ACK 置為一。
    • SYN=1:當SYN=1,ACK=0時,表示當前報文段是一個連接請求報文。當SYN=1,ACK=1時,表示當前報文段是一個同意建立連接的應答報文。
    • FIN=1:該字段為一表示此報文段是一個釋放連接的請求報文。
    • URG=1 : 該字段為一表示本數據報的數據部分包含緊急信息,是一個高優先級數據報文,此時緊急指針有效。緊急數據一定位於當前數據包數據部分的最前面,緊急指針標明瞭緊急數據的尾部。
    • PSH=1 :該字段為一表示接收端應該立即將數據 push 給應用層,而不是等到緩衝區滿後再提交。
    • RST=1:該字段為一表示當前 TCP 連接出現嚴重問題,可能需要重新建立 TCP 連接,也可以用於拒絕非法的報文段和拒絕連接請求。

1.2 三次握手

【學習總結】TCP協議理解

簡單的說:

  • 第一次握手

    • SYN = 1, seq(client) = x
    • 客戶端向服務端發送連接請求報文段。該報文段中包含自身的數據通訊初始序號。請求發送後,客戶端便進入 SYN-SENT 狀態。
  • 第二次握手

    • SYN = 1,ACK = 1,確認序號 = x+1, seq(server) = y
    • 服務端收到連接請求報文段後,如果同意連接,則會發送一個應答,該應答中也會包含自身的數據通訊初始序號,發送完成後便進入 SYN-RECEIVED 狀態
  • 第三次握手

    • ACK = 1,確認序號 = y+1, seq(client) = x + 1
    • 客戶端收到連接同意的應答後,還要向服務端發送一個確認報文。客戶端發完這個報文段後便進入ESTABLISHED 狀態,服務端收到這個應答後也進入 ESTABLISHED 狀態,此時連接建立成功。

1.3 為什麼不用兩次握手?

[!NOTE]
主要是為了防止已經失效的連接請求報文突然又傳送到了服務器,從而產生資源浪費。

採用兩次握手,那麼若Client向Server發起的包A1如果在傳輸鏈路上遇到的故障,導致傳輸到Server的時間相當滯後,在這個時間段由於Client沒有收到Server的對於包A1的確認,那麼就會重傳一個包A2,假設服務器正常收到了A2的包,然後返回確認B2包。由於沒有第三次握手,這個時候Client和Server已經建立連接了。再假設A1包隨後在鏈路中傳到了Server,這個時候Server又會返回B1包確認,但是由於Client已經清除了A1包,所以Client會丟棄掉這個確認包,但是Server會保持這個相當於“殭屍”的連接,造成Server的網絡資源浪費。

形象解釋:

  • 1,客戶發一個曖昧的消息,給服務員
  • 2,服務員收到,看了消息,很高興,馬上回信(此時客戶還不知道服務收到)
  • 3,客戶特別高興收到服務員關係確認的消息,(但是服務員還不知道客戶收到了,如果沒收到得重發,理論上來說,直到- 海枯石爛=-=)
  • 4,服務員終於收到了客戶關係確認的消息,懸著的心終於放下了
  • 5,於是客戶跟服務員真正建立了 一條可靠的通道,畢竟兩人都知道那是行得通的。。。

所以至少得三次才能確認關係。不用三次的話,server不能確定client是否收到自己的消息
如果server沒有收到迴應,可能的原因有兩種:

  • client根本沒收到消息,
  • 或者client響應了,但server沒收到結果

如果你用過對講機你就會明白:

  • C ->S: 你能聽到嗎?
  • S->C: 聽到。你能聽到我嗎?
  • C->S:聽到。

如果採用的是三次握手,就算是那一次失效的報文傳送過來了,服務端接受到了那條失效報文並且回覆了確認報文,但是客戶端不會再次發出確認。由於服務器收不到確認,就知道客戶端並沒有請求連接,就不會建立新的連接造成資源浪費。

1.3 為什麼建立連接是三次握手,四次不可以嗎

第一次握手:

Client什麼都不能確認   
Server確認了對方發送正常

第二次握手:

Client確認:自己發送/接收正常,對方發送/接收正常
Server確認:自己接收正常 ,對方發送正常

第三次握手:

Client確認:自己發送/接收正常, 對方發送/接收正常
Server確認:自己發送/接收正常,對方發送/接收正常

所以通過三次握手確認雙方收發功能都正常,四次也可以但是顯得比較多餘

1.4 四次揮手

【學習總結】TCP協議理解

TCP 是全雙工的,在斷開連接時兩端都需要發送 FIN 和 ACK。

  • 第一次揮手

    • 若客戶端 A 認為數據發送完成,則它需要向服務端 B 發送連接釋放請求。
  • 第二次揮手

    • B 收到連接釋放請求後,會告訴應用層要釋放 TCP 鏈接。然後會發送 ACK 包,並進入 CLOSE_WAIT 狀態,表示 A 到 B 的連接已經釋放,不接收 A 發的數據了。但是因為 TCP 連接時雙向的,所以 B 仍舊可以發送數據給 A。
  • 第三次揮手

    • B 如果此時還有沒發完的數據會繼續發送,完畢後會向 A 發送連接釋放請求,然後 B 便進入LAST-ACK狀態。
    • PS:通過延遲確認的技術(通常有時間限制,否則對方會誤認為需要重傳),可以將第二次和第三次揮手合併,延遲 ACK 包的發送。
  • 第四次揮手

    • A 收到B返回的釋放請求後,向 B 發送確認應答,此時 A 進入 TIME-WAIT 狀態。該狀態會持續 2MSL(最大段生存期,指報文段在網絡中生存的時間,超時會被拋棄) 時間,若該時間段內沒有 B 的重發請求的話,就進入 CLOSED 狀態。當 B 收到確認應答後,也便進入 CLOSED 狀態。

1.5 為什麼 A 要進入 TIME-WAIT 狀態,等待 2MSL 時間後才進入 CLOSED 狀態?

為了保證 B 能收到 A 的確認應答。若 A 發完確認應答後直接進入 CLOSED 狀態,如果確認應答因為網絡問題一直沒有到達,那麼會造成 B 不能正常關閉。

如果A發送完ACK應答之後直接進入CLOSED狀態的話,如果因為網絡延遲問題這個應答丟失或在2MSL內還沒有到達B的話,那麼B等待超時之後就會重新發送一個FIN包,但是此時A已經關閉了,永遠得不到A的響應,從而導致B永遠不能正常關閉

1.6 為什麼需要TIME_WAIT狀態

1.6.1 為實現TCP這種全雙工連接的可靠釋放

這樣可讓TCP再次發送最後的ACK以防這個ACK丟失(另一端超時並重發最後的FIN)這種2MSL等待的另一個結果是這個TCP連接在2MSL等待期間,定義這個連接的插口(客戶的IP地址和端口號,服務器的IP地址和端口號)不能再被使用。這個連接只能在2MSL結束後才能再被使用。

1.6.2 為使舊的數據包在網絡因過期而消失

每個具體TCP實現必須選擇一個報文段最大生存時間MSL。它是任何報文段被丟棄前在網絡內的最長時間。

1.7 為什麼建立連接是三次握手,關閉連接確是四次揮手呢?

  1. 建立連接的時候, 服務器在LISTEN狀態下,收到建立連接請求的SYN報文後,把ACK和SYN放在一個報文裡發送給客戶端。

  2. 而關閉連接時,服務器收到對方的FIN報文時,僅僅表示對方不再發送數據了但是還能接收數據,而自己也未必全部數據都發送給對方了

2. ARQ (超時重傳)協議

[!NOTE]
通過確認和超時機制保證了數據的正確送達,ARQ 協議包含停止等待 ARQ連續 ARQ

2.1 停止等待 ARQ

正常傳輸過程

只要 A 向 B 發送一段報文,都要停止發送並啟動一個定時器,等待對端迴應,在定時器時間內接收到對端應答就取消定時器併發送下一段報文。

當報文丟失或出錯:

報文傳輸的過程中丟包: 這時候超過定時器設定的時間就會再次發送丟包的數據直到對端響應,所以需要每次都備份發送的數據。

傳輸過程中報文出錯: 對端會拋棄該報文並等待 A 端重傳。

PS:一般定時器設定的時間都會大於一個 RTT 的平均時間。

ACK 超時或丟失:

對端傳輸的應答也可能出現丟失或超時的情況。那麼超過定時器時間 A 端照樣會重傳報文。這時候 B 端收到相同序號的報文會丟棄該報文並重傳應答,直到 A 端發送下一個序號的報文。

這個協議的缺點就是傳輸效率低,在良好的網絡環境下每次發送報文都得等待對端的 ACK 。

2.2 連續 ARQ

在連續 ARQ 中,發送端擁有一個發送窗口,可以在沒有收到應答的情況下持續發送窗口內的數據,這樣相比停止等待 ARQ 協議來說減少了等待時間,提高了效率。

2.2.1 累計確認

連續 ARQ 中,接收端會持續不斷收到報文。如果和停止等待 ARQ 中接收一個報文就發送一個應答一樣,就太浪費資源了。通過累計確認,可以在收到多個報文以後統一回復一個應答報文。報文中的 ACK 可以用來告訴發送端這個序號之前的數據已經全部接收到了,下次請發送這個序號 + 1的數據。

但是累計確認也有一個弊端。在連續接收報文時,可能會遇到接收到序號 5 的報文後,並未接到序號 6 的報文,然而序號 7 以後的報文已經接收。遇到這種情況時,ACK 只能回覆 6,這樣會造成發送端重複發送數據,這種情況下可以通過 Sack 來解決。

2.2.2 滑動窗口

上面講到了發送窗口。在 TCP 中,兩端都維護著窗口:分別為發送端窗口和接收端窗口。

發送端窗口包含已發送但未收到應答的數據和可以發送但是未發送的數據。

【學習總結】TCP協議理解

發送端窗口是由接收窗口剩餘大小決定的。接收方會把當前接收窗口的剩餘大小寫入應答報文,發送端收到應答後根據該值和當前網絡擁塞情況設置發送窗口的大小,所以發送窗口的大小是不斷變化的。

當發送端接收到應答報文後,會隨之將窗口進行滑動

滑動窗口實現了流量控制。接收方通過報文告知發送方還可以發送多少數據,從而保證接收方能夠來得及接收數據。

【學習總結】TCP協議理解

Zero 窗口

在發送報文的過程中,可能會遇到對端出現零窗口的情況。在該情況下,發送端會停止發送數據,並啟動 persistent timer 。該定時器會定時發送請求給對端,讓對端告知窗口大小。在重試次數超過一定次數後,可能會中斷 TCP 鏈接。

3. 擁塞處理

[!NOTE]
擁塞處理和流量控制不同,後者是作用於接收方,保證接收方來得及接受數據。而前者是作用於網絡,防止過多的數據擁塞網絡,避免出現網絡負載過大的情況。

擁塞處理包括了四個算法,分別為:慢開始,擁塞避免,快速重傳,快速恢復。

【學習總結】TCP協議理解

3.1 慢開始算法

[!NOTE]
慢開始算法,顧名思義,就是在傳輸開始時將發送窗口從1開始指數級擴大,從而避免一開始就傳輸大量數據導致網絡擁塞。

慢開始算法步驟具體如下

  1. 連接初始設置擁塞窗口(Congestion Window) 為 1 MSS(一個分段的最大數據量)
  2. 每過一個 RTT (往返時延) 就將窗口大小乘二
  3. 指數級增長肯定不能沒有限制的,所以有一個閾值限制,當窗口大小大於閾值時就會啟動擁塞避免算法

3.2 擁塞避免算法

[!NOTE]
擁塞避免算法相比簡單點,每過一個 RTT 窗口大小隻加一,這樣能夠避免指數級增長導致網絡擁塞,慢慢將大小調整到最佳值。

【學習總結】TCP協議理解

在傳輸過程中可能定時器超時的情況,這時候 TCP 會認為網絡擁塞了,會馬上進行以下步驟:

  • 將閾值設為當前擁塞窗口的一半
  • 將擁塞窗口設為 1 MSS
  • 啟動擁塞避免算法

3.3 快速重傳

快速重傳一般和快恢復一起出現。一旦接收端收到的報文出現失序的情況,接收端只會回覆最後一個順序正確的報文序號(沒有 Sack 的情況下)。如果收到三個重複的 ACK,無需等待定時器超時再重發而是啟動快速重傳。具體算法分為兩種:

4. TCP 小結

4.1 為什麼TCP這麼複雜?

[!NOTE]
因為既要保證可靠性, 同時又要儘可能提高性能

4.1.1 保證可靠性的機制

  • 校驗和
  • 序列號(按序到達)
  • 確認應答
  • 超時重傳
  • 連接管理
  • 流量控制
  • 擁塞控制

4.1.2 提高性能的機制

  • 滑動窗口
  • 快速重傳
  • 延遲應答
  • 捎帶應答

4.2 定時器

  • 超時重傳定時器
  • 保活定時器
  • TIME_WAIT定時器

4.3 基於 TCP 的應用層協議

  • HTTP
  • HTTPS
  • SSH
  • Telnet
  • FTP
  • SMTP

相關文章

Python植物大戰殭屍代碼實現:圖片加載和顯示切換

《碼了4個小時》SonarQube+Jenkins代碼質量檢查工具攻略大全

從客戶端角度窺探小程序架構

如何用上webpack/gulp/rollup,搭建一個基於Vue的UI庫腳手架