我今天才知道,原來TCP爲了保證可靠傳輸做了這麼多 前言 1.TCP 可靠傳輸概覽 2. 校驗和 3. 序列號和確認應答機制 4. 重傳機制 4. 滑動窗口協議 5. 流量控制 6. 擁塞控制

前言

本節內容有點多,不過關於 TCP 的話,除了三四次握手就是可靠傳輸了,高頻重點知識點,大家還是搞清楚比較好。

1.TCP 可靠傳輸概覽

首先解釋一下,什麼是可靠傳輸:可靠傳輸就是保證接收方收到的字節流和發送方發出的字節流是完全一樣的。

網絡層是沒有可靠傳輸機制的,儘自己最大的努力進行交付。而傳輸層使用 TCP 實現可靠傳輸,TCP 保證可靠傳輸的機制有如下幾種:

  • 1)校驗和 Checksum(稍作了解即可)
  • 2)序列號和確認應答機制(重要)
  • 3)重傳機制(重要)
  • 4)流量控制(滑動窗口協議)(非常重要)
  • 5)擁塞控制(重要)

以上除了校驗和大家可以只稍作了解之外,其他都是非常重要的,務必爛熟於心。

2. 校驗和

所謂 TCP 的校驗和(Checksum)就是說:由發送端計算待發送 TCP 報文段的校驗和,然後接收端對接收到的 TCP 報文段驗證其校驗和(TCP 的校驗和是一個端到端的校驗和)。其目的是爲了發現 TCP 的首部和數據在發送端到接收端之間是否發生了變動。如果接收方檢測到校驗和有差錯,則該 TCP 報文段會被直接丟棄。

關於校驗和是如何計算和驗證的,並非高頻重點知識,本文就不詳細解釋了,感興趣的童鞋可自行百度

TCP 在計算校驗和時,需要加上一個 12 字節的僞首部。

其實 UDP 也有校驗和機制,只不過是可選的,而 TCP 的校驗和是必須的,TCP 和 UDP 在計算校驗和時都需要加上一個 12 字節的僞首部。

解釋下僞首部的概念,僞首部的數據是從 IP 數據報頭獲取的,共有 12 字節,包含如下信息:源 IP 地址、目的 IP 地址、保留字節 (置 0)、傳輸層協議號 (TCP 是 6)、TCP 報文長度 (首部 + 數據):

僞首部是爲了增加 TCP 校驗和的檢錯能力:如根據目的 IP 地址檢查這個 TCP 報文是不是傳給我的、根據傳輸層協議號檢查傳輸層協議是否選對了...... 僞首部只在校驗的時候使用。

3. 序列號和確認應答機制

TCP 報文段的首部中有一個序號字段,在之前的文章 關於 TCP 三次握手和四次揮手,滿分回答在此 已經解釋過:指的是該報文段第一個字節的序號(一個字節佔一個序號)

確認應答機制就是接收方收到 TCP 報文段後就會返回一個確認應答消息

確認應答機制和重傳機制不分家,兩者緊密相連。下面我們詳細講解一下重傳機制

4. 重傳機制

在錯綜複雜的網絡,並不一定能如上圖那麼順利地傳輸報文,報文存在丟失的可能性。報文丟失的可能因素有很多種,包括應用故障,路由設備過載,或暫時的服務宕機。報文級別速度是很高的,通常來說報文的丟失是暫時的,因此 TCP 能夠發現和恢復報文丟失顯得尤爲重要。

重傳機制是 TCP 最基本的錯誤恢復功能,常見的重傳機制有如下:

  • 超時重傳
  • 快速重傳

① 超時重傳

大概一說到重傳大家第一個想到的就是超時重傳吧。超時重傳就是 TCP 發送方在發送報文的時候,設定一個定時器,如果在規定的時間內沒有收到接收方發來的 ACK 確認報文,發送方就會重傳這個已發送的報文段。

對於發送方沒有正確接收到接收方發來的 ACK 確認報文的情況,有以下兩種(也就是在這兩種情況下會發生超時重傳):

  • 第一種情況:報文段丟失
  • 第二種情況:接收方的 ACK 確認報文丟失

超時重傳時間我們一般用 RTO(Retransmission Timeout) 來表示,那麼,這個 RTO 設置爲多少最合適呢,也就是說經過多長時間進行重傳最好?

在這之前,我們先講解一下 RTT(Round-Trip Time 往返時延) 的概念:RTT 就是數據從網絡一端傳送到另一端所需的時間,也就是報文段的往返時間。

顯然,⭐ 超時重傳時間 RTO 的值應該略大於報文往返 RTT 的值:

我們可以假想一下,如果超時重傳時間 RTO 遠大於或小於 RTT,會發生什麼情況:

  • RTO 遠大於 RTT:網絡的空閒時間增大,降低了網絡傳輸效率
  • RTO 小於 RTT:不必要的重傳,導致網絡負荷增大

如果超時重傳的數據又超時了該怎麼辦呢?TCP 的策略是重傳的超時間隔加倍。

也就是說,每進行一次超時重傳,都會將下一次重傳的超時時間間隔設爲先前值的兩倍。

超時觸發重傳存在的問題是,超時週期可能相對較長。有沒有一種機制可以減少超時重傳的等待時間呢?於是 「快速重傳」 機制應運而生

快速重傳

快速重傳(Fast Retransmit)機制不以時間爲驅動,而是以數據驅動重傳。

快速重傳機制的原理:每當接收方收到比期望序號大的失序報文段到達時,就向發送方發送一個冗餘 ACK,指明下一個期待字節的序號。

舉個例子:發送方已經發送 1、2、3、4、5報文段

  • 接收方收到報文段 1,返回 1 的 ACK 確認報文(確認號爲報文段 2 的第一個字節)
  • 接收方收到報文段 3,仍然返回 1 的 ACK 確認報文(確認號爲報文段 2 的第一個字節)
  • 接收方收到報文段 4,仍然返回 1 的 ACK 確認報文(確認號爲報文段 2 的第一個字節)
  • 接收方收到報文段 5,仍然返回 1 的 ACK 確認報文(確認號爲報文段 2 的第一個字節)
  • 接收方收到 3 個對於報文段 1 的冗餘 ACK,認爲報文段 2 丟失,於是重傳報文段 2
  • 最後,接收方收到了報文段 2,此時因爲報文段 3、4、5 都收到了,所以返回 6 的 ACK 確認報文(確認號爲報文段 6 的第一個字節)

一圖勝千言:

4. 滑動窗口協議

可以說不知道滑動窗口協議 = 不知道 TCP。該知識點的分量之重,大家一定好好把握。

① 累積確認

上文講快速重傳的時候,不知道大家有沒有注意到這句話 “ 最後,接收方收到了報文段 2,此時因爲報文段 3、4、5 都收到了,所以返回 6 的 ACK 確認報文 ”。

爲什麼這裏會直接返回報文段 6 的確認應答呢,之前我們不是說每發送一個 TCP 報文段,就進行一次確認應答嗎(只有收到了上一個報文段的確認應答後才能發送下一個報文段的)?按照這個模式,我們應該先返回報文段 3 的確認應答啊。

其實只有收到了上一個報文段的確認應答後才能發送下一個報文段的這種模式效率非常低下。每個報文段的往返時間越長,網絡的吞吐量就越低,通信的效率就越低。

舉個例子:如果你說完一句話,我在處理其他事情,沒有及時回覆你,你就等着我做完其他事情後回覆你,你才能說下一句話,很顯然這不現實。

爲此,TCP 引入了 窗口 的概念。窗口大小就是指無需等待確認應答,可以繼續發送數據的最大值。

⭐ 窗口的實現實際上是操作系統開闢的一個緩衝區,發送方在等待確認應答報文返回之前,必須在緩衝區中保留已發送的數據。如果在規定時間間隔內收到確認應答報文,就可以將數據從緩衝區中清除。

假設窗口大小爲 3 個 TCP 段,那麼發送方就可以「連續發送」 3 個 TCP 段,並且中途即使有 ACK響應報文丟失,也可以通過「下一個確認應答進行確認」。

如下圖:ACK 300 即使丟失了,也不會進行數據重發,可以通過下一個確認應答進行確認。只要發送方收到了 ACK 400 的確認應答,就意味着 400 之前的所有數據「接收方」都收到了。這個模式就叫累積確認或者累積應答。

② 發送方的滑動窗口

該小節圖片均來自公衆號:小林 Coding

我們先來看看發送方的窗口,下圖就是發送方緩存的數據,根據處理的情況分成四個部分:

  • 已發送並收到 ACK 確認應答的數據
  • 已發送但未收到 ACK 確認應答的數據
  • 未發送但總大小在接收方處理範圍內的數據
  • 未發送但總大小超過接收方處理範圍的數據

當發送方把數據全部發送出去後,可用窗口的大小就爲 0 了,表明可用窗口耗盡,在沒收到 ACK 確認之前無法繼續發送數據:

當收到之前發送的數據 32~36 字節的 ACK 確認應答後,如果發送窗口的大小沒有變化,則滑動窗口往右邊移動 5 個字節,因爲有 5 個字節的數據被確認應答,接下來 52~56 字節又變成了可用窗口,那麼後續也就可以發送 52~56 這 5 個字節的數據了:

③ 接收方的滑動窗口

接收方的滑動窗口可分爲三個部分:

  • 已成功接收並確認的數據
  • 未收到數據但可以接收的數據
  • 未收到數據且不可以接收的數據(超出接收方窗口大小)

同樣的,接收方的滑動窗口在成功接收並確認的數據後,窗口右移。

5. 流量控制

想象一下這個場景:主機 A 一直向主機 B 發送數據,不考慮主機 B 的接收能力,則可能導致主機 B 的接收緩衝區滿了而無法再接收數據,從而導致大量的數據丟包,引發重傳機制。而在重傳的過程中,若主機 B 的接收緩衝區情況仍未好轉,則會將大量的時間浪費在重傳數據上,降低傳送數據的效率。

所以引入了流量控制機制,主機 B 通過告訴主機 A 自己接收緩衝區的大小,來使主機 A 控制發送的數據量。總結來說:所謂流量控制就是控制發送方發送速率,保證接收方來得及接收。

TCP 實現流量控制主要就是通過 滑動窗口協議。

上文我們提到了滑動窗口大小,但是沒說窗口大小在哪裏設置,其實這個和 TCP 報文首部中的 窗口大小 Window 字段有關。回顧一下上篇文章 關於 TCP 三次握手和四次揮手,滿分回答在此 中講過的 TCP 報文的首部格式,其中就有一個 16 位的 窗口大小 Window 字段:

該字段的含義是指自己接收緩衝區的剩餘大小,於是發送端就可以根據這個接收端的處理能力來發送數據,而不會導致接收端處理不過來。

所以,通常來說窗口大小是由接收方來決定的。

這段話大家一定要理解哦:接收端會在發送 ACK 確認應答報文時,將自己的即時窗口大小(接收窗口 rwnd)填入,並跟隨 ACK 報文一起發送出去。而發送方根據接收到的 ACK 報文中的窗口大小的值改變自己的發送速度。如果接收到窗口大小的值爲 0,那麼發送方將停止發送數據。並定期地向接收端發送窗口探測數據段,提醒接收端把窗口大小告訴發送端。

一圖勝前言:

6. 擁塞控制

該小節圖片均來自公衆號:小林 Coding

所謂擁塞就是說:在某段時間,對網絡中某一資源的需求超過了該資源所能提供的可用部分(即 需大於供),網絡的性能變差。

如果網絡出現擁塞,TCP 報文可能會大量丟失,此時就會大量觸發重傳機制,從而導致網絡擁塞程度更高,嚴重影響傳輸。

其實只要「發送方」沒有在規定時間內接收到 ACK 應答報文,也就是觸發了重傳機制,就會認爲網絡出現了擁塞。

因此當出現擁塞時,應當控制發送方的速率。這一點和流量控制很像,但是出發點不同。

流量控制是爲了讓接收方能來得及接收,而擁塞控制是爲了降低整個網絡的擁塞程度,防止過多的數據注入到網絡中。

爲了調節發送方所要發送數據的量,定義了「擁塞窗口 cwnd」的概念。擁塞窗口是發送方維護的一個狀態變量,它會根據網絡的擁塞程度動態變化:

  • 只要網絡中出現了擁塞,cwnd 就會減少
  • 若網絡中沒有出現擁塞,cwnd 就會增大

在引入擁塞窗口概念之前,發送窗口大小和接收窗口大小基本是相等的關係(取決於接收窗口大小)。引入擁塞窗口後,發送窗口的大小就等於擁塞窗口和接收窗口的最小值。

TCP 的擁塞控制採用了四種算法:

  • 慢開始
  • 擁塞避免
  • 快重傳
  • 快恢復

下面詳細講解這四種算法

① 慢開始

慢開始的思路就是:TCP 在剛建立連接完成後,如果立即把大量數據字節注入到網絡,那麼很有可能引起網絡阻塞。好的方法是先探測一下,一點一點地提高發送數據包的數量,即由小到大逐漸增大擁塞窗口數值。cwnd 初始值爲 1,每經過一個傳播輪次,cwnd 加倍(指數增長)。

當然不能一直執行慢啓動,這裏會設置一個慢啓動輪限 ssthresh 狀態變量:

  • 當 cwnd < ssthresh 時,繼續使用慢啓動算法
  • 當 cwnd >= ssthresh 時,開始使用「擁塞避免算法」

② 擁塞避免

擁塞避免算法的思路是讓擁塞窗口 cwnd 緩慢增大,即每經過一個往返時間 cwnd 加 1。

注意,無論是慢開始階段還是擁塞避免,只要出現了網絡擁塞(觸發超時重傳機制),慢開始輪限 sshresh 和 擁塞窗口大小 cwnd 的值會發生變化(乘法減小):

  • ssthresh 設爲 cwnd/2
  • cwnd 重置爲 1

由於擁塞窗口大小重置爲 1 了,所以就會重新開始執行慢啓動算法。

③ 快重傳和快恢復

快速重傳和快速恢復算法一般同時使用。

當觸發快速重傳機制,即接收方收到三個重複的 ACK 確認的時候,就會執行快重傳算法(觸發快速重傳機制和超時重傳機制的情況不同,TCP 認爲觸發快速重傳的情況並不嚴重,因爲大部分沒丟,只丟了一小部分),快速重傳做的事情有:

  • cwnd = cwnd/2
  • ssthresh = cwnd
  • 重新進入擁塞避免階段

後來的 “快速恢復” 算法是在上述的“快速重傳”算法後添加的,當收到 3 個重複ACK時,TCP 最後進入的不是擁塞避免階段,而是快速恢復階段。

快速恢復的思想是“數據包守恆”原則,即同一個時刻在網絡中的數據包數量是恆定的,只有當“老”數據包離開了網絡後,才能向網絡中發送一 個“新”的數據包,如果發送方收到一個重複的 ACK,那麼根據 TCP 的 ACK 機制就表明有一個數據包離開了網絡,於是 cwnd 加 1。如果能夠嚴格按照該原則那麼網絡中很少會發生擁塞,事實上擁塞控制的目的也就在修正違反該原則的地方。

具體來說快速恢復的主要步驟是:

  • 把 cwnd 設置爲 ssthresh 的值加 3,然後重傳丟失的報文段,加 3 的原因是因爲收到 3 個重複的 ACK,表明有 3 個“老”的數據包離開了網絡。
  • 再收到重複的 ACK 時,擁塞窗口 cwnd 增加 1
  • 當收到新的數據包的 ACK 時,把 cwnd 設置爲第一步中的 ssthresh 的值。原因是因爲該 ACK 確認了新的數據,說明從重複 ACK 時的數據都已收到,該恢復過程已經結束,可以回到恢復之前的狀態了,也即再次進入擁塞避免狀態。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章