傳輸控制協議(Transmission Control Protocol,TCP)基本認識
TCP 所扮演的角色
TCP 位於傳輸層,它提供了運行在不同主機上的應用行程之間(彼此距離非常遙遠,可能彼此位於地球的任一側)的邏輯通信(也就是在通信雙方的傳輸層間好像有一條直接相連的通道一樣),對上(應用層)提供了可靠傳輸服務,對下(網路層)將其不可靠 IP 服務轉換成了一種行程間的可靠傳輸服務。
§ TCP 特性
- 基於連接的傳輸協議:通信雙方要相互通信前,首先必須先建立連接(三次握手),連接建立完後才能進行資料傳輸,最後沒有資料要進行傳輸了就要斷開連接(四次揮手)。
- 全雙工(full duplex):即在一個通信中進行資料傳輸是雙向的。
- 可靠性傳輸服務:通過檢驗和、序列號、確認應答、重發控制、連接管理以及流量控制等等機制實現。
- 位於傳輸層,為點對點(只能單播,不能廣播、多播)服務,即在單個發送方與對應的單個接收方之間建立邏輯通信。
TCP 報文段首部格式
這裡只針對幾個我認為比較重要的欄位進行介紹,至於其他欄位我就不多加介紹了,如下圖所示:
源端口號:發送給目標計算機的計算機上的應用程式的端口號。
目標端口號:目標計算機上的應用程式端口號。
序列號:每個報文段所攜帶的資料,其首個位元組序列號即是該報文段的序列號,用來使接收方檢測丟失的分組及分組重複問題。
確認號:指下一次「期望」收到的報文段的序列號,表示該序列號之前的所有資料都已經正確的收到了。
窗口:以位元組為單位,用來告知通信對方我當前的接收窗口大小,也就是說我的接收緩存可用空間大小。
旗標欄位(Flag Field):
- ACK:當 ACK=1 時,表示確認號欄位有效,反之 ACK = 0 時,表示確認號欄位無效。
- RST:重置連接欄位,當 RST=1 時,表示 TCP 連接出現異常,必須強制斷開連接。
- SYN:同步欄位,用於雙方建立 TCP 連接時。當 SYN=1 時,表示希望建立連接。
- FIN:用於釋放連接,當 FIN=1 時,表示希望斷開連接。
可靠性傳輸的一些原理
序列號與確認號
使用 TCP 相互通信的雙方在進行資料傳輸時,序列號與確認號這兩個首部欄位扮演著重要的角色,為什麼會這麼說呢?序列號可以很明確地讓接收方知道自己已經接收了哪些報文段(就算未按序到達也能正確排序),且被重複傳來的報文段接收方能檢測出並丟棄,而確認號則是可以讓發送方知道接收方已經接收了哪些報文段,而避免不必要的重傳,也可以告知發送方下一個該傳過來的報文段是哪一個。
§ 序列號(Sequence Number, SEQ)
這裡給出一個例子,假如說主機 A 上的某個行程透過 TCP 連接向主機 B 上的一個行程發送資料,假定這資料是由一個包含 500000 位元組的文件組成,其中最大報文段長度(MSS) 為 1000 位元組。現在 TCP 連接建立成功了,TCP 會為這個資料的每一個位元組進行編號,其資料的首個位元組的序列號為 1000(這裡的 1000 是假設的,這是 TCP 連接建立時隨機的編號,每次不一定會是一樣的號碼,我們稱其為初始序列號),接著每個位元組都會被按順序編號(這個我們稱之為位元組序列號),然後每一個報文段序列號即是該報文段的資料的首個位元組序號,如下圖所示:
三種類型序列號
(1)位元組序列號
TCP 為要傳送的位元組串流(資料),每個位元組按順序編號,也就是說每個位元組皆有一個序號,因此這個序號稱為位元組序號。
(2)報文段序列號
每個報文段所攜帶的資料,其首個位元組序列號即是該報文段的序列號,也就是會被填入首部序列號的號碼,因此以整體報文段來看我們稱它為這個報文段的序列號。
(3)初始化序列號
TCP 在建立連接的時候,序列號不是從 0 開始的,而是隨機產生一個號碼的,這個號碼我們稱為初始化序列號。
§ 一些序列號與確認號的案例
(1)未按序抵達的報文段
如上圖所示,以下將說明:「透過序列號確定未按序抵達的報文段的順序」
- seq = 1 的報文段在傳輸過程中延遲了,接收方先收到 seq = 101 的報文段,將其記錄起來然後向發送方發送確認報文段(ack = 1)。
- 接收方又再接收到一個 seq = 201 的報文段,一樣把其記錄下來然後向發送方發送確認報文段(ack = 1)。
- 此時接收方終於收到延遲的報文段(seq = 1)了,接收方會根據其報文段的序列號進行排序,也正因為是序列號,所以才能正確地將資料傳送給應用層讀取。
(2)收到重複的報文段
如上圖所示,以下將說明:「接收方是如何對重複的報文段進行處理」
- 一開始 seq = 1 的報文段被發送至接收方,然後超時計時器計時。
- 接收方收到 seq = 1 的報文段後,將其記錄,然後向發送方傳送一個 ACK 確認報文段,並期望下次收到 seq = 101 的報文段。
- 由於確認報文段在傳輸過程中丟失了,經過一段時間後,超時重傳時間到了,對 seq = 1 的報文段進行重傳。
- 接收方收到 seq = 1 的報文段後,發現該報文段已經接收過了,於是丟棄,然後向發送方發出一個 ACK 確認報文段。
(3)一個報文段被正確地接收
如下圖可以看到 A 接收到來自 B 的確認報文段表示已經接收到了 seq = 1 的報文段,這是採逐個確認的
(4)多個報文段被正確地接收
如下圖可以看到 A 接收到來自 B 的確認報文段表示已經接收到報文段,其中有一個確認報文段 ack = 301 在途中丟失了,但是它並不會重傳 seq = 201 的報文段,因為透過確認報文段 ack = 401 來確認,這是採累積確認的。
超時重傳
為 TCP 提供了避免發送方發給接收方的報文段丟失(當然可能接收方有收到報文段,但來自接收方的確認報文段丟失,又或者網路延遲等等都有可能),以確保資料的完整性。超時重傳會發生在以下兩種情形,如下圖所示:
這裡要特別澄清一件事,TCP 不是為每一個已發送但未被確認的報文段就與一個重傳定時器相關聯,而是僅使用一個定時器,與最早未被確認的報文段相關聯。
§ 超時重傳時間的選擇
超時重傳時間(Retransmission Timeout,RTO)的選擇是 TCP 最複雜的問題之一,該如何選擇呢?讓我們來看一下以下一些情況:
首先我們先來了解往返時間(Round Trip Time,RTT)
主機 A 發送 TCP 資料報文段給主機 B ,此時主機 A 會記錄當前時間,主機 B 收到後回傳 TCP 確認報文段給主機 A,當主機 A 收到確認報文段之後也記錄當前時間,這兩個時間的差值就是報文段的往返時間。
超時重傳時間的長短所引發的情形
(1)超時重傳時間過短
如果說超時重傳時間(RTO)設置的比往返時間(RTT)還要短,會引起報文段不必要的重傳,即使在資料傳輸時資料是沒有丟失的,但卻因為這個原因導致重傳,這將使網路的負荷增大。
(2)超時重傳時間過長
如果說超時重傳時間(RTO)設置的比往返時間(RTT)還要長,如下圖假設報文段 A 在傳輸過程中丟失了(圖片有畫出報文段 A 的往返是為了要凸顯往返時間),卻因為超時重傳時間過長,在這個期間使網路的空閒時間增大,進而導致傳輸效率低下。
現在我們已經知道超時重傳時間(RTO)的選擇不能過長或過短,那該如何獲取適當的超時重傳時間(RTO)呢?以下我們來談論一下:
Step1:計算往返時間(RTT)
Step2:計算加權平均往返時間(RTTS)
- 其中 0 ≦ α<1,推薦的 α 值為 0.125
Step3:計算偏差的加權平均往返時間(RTTD)
Step4:求得超時重傳時間(RTO)
快速重傳(fast retransmit)
前面所介紹的超時重傳所存在的問題之一是如果說超時週期相對來說較長,將會造成端到端的時延,所以現在希望可以在這個超時重傳時間內,就先進行重傳丟失的報文段,那我們可以利用快速重傳來解決,也就是說發送方在超時事件發生之前,通過重複 ACK(duplicate ACK)再次確認某個丟失的報文段,以進行重傳這個丟失的報文段。如下圖說明:
- 主機 A:發送方;主機 B:接收方
- 現在發送方傳給接收方 seq = 1 的報文段抵達了,接收方收到了回傳 ack 101 給發送方。
- 發送方傳給接收方 seq = 101 的報文段中途丟失了。
- 發送方後面傳給接收方 seq = 201、seq = 301、seq = 401 的報文段都到了,它們都會回傳 ack 101。
- 當發送方接收到了三個重複確認 ack 101 ,就知道 seq = 101 的報文段還沒被接收方收到,將會在超時之前重傳丟失的報文段
選擇確認(Selective ACK, SACK)
TCP 接收方只能對按序收到的報文段的最高序列號給出確認,對於超時重傳而言,如果說發送方發生超時重傳,那麼接收方將之前已經收到的但是未按序到達的報文段也將會被重傳,整體來說發送方發送的那些被接收方接收的未按序到的報文段等於做白工了,然而對於快速重傳來說它只解決一個問題,那就是超時時間問題,在超時時間內快速發送 3 個相同的 ACK 報文段,以避免超時重傳的發生,但依然還是面臨問題,如果說在這個傳輸期間,多個報文段丟失了,那它是不是要為每個丟失的報文段,進行發送 3 個相同的 ACK 報文段,那這樣的重傳顯得效率很低,那麼是否有更好的機制呢?顯然是有的,我們可以採用選擇確認。
§ 選擇確認的使用
如上圖所示,以下將說明:「通過選擇確認來重傳丟失的報文段」
- 發送方一開時同時發送資料為 1 ~ 100、101 ~ 200、201 ~ 300、301 ~ 400 及401 ~ 500的報文段,達到發送窗口上限,不能再發送資料。其中報文段資料為 101 ~ 200、301 ~ 400 的報文段丟失了。
- 接收方收到資料為 1 ~ 100 的報文段後,向發送方響應了一個 ack = 101 的確認報文段,然後發送方收到了後,1 ~ 100 的報文段從緩存中丟棄,發送窗口向前移動,此時 cwnd 的值加 1 維持在 6(假定的值,方便討論),然後可以發送資料為 501 ~ 600 及 601 ~ 700 的報文段。
- 接收方陸續收到其他報文段,唯獨資料為101 ~ 200 及 301 ~ 400 的報文段沒有收到,所有接收方在回傳確認報文段時,會將已經收到的資料記錄在確認報文段當中,可以從上圖發現。
- 當發送方收到三個相同的 ack = 101 的確認報文段後,觸發快速重傳機制,發送方會根據 SACK 信息進行丟失的報文段重傳,如上圖所示, 101 ~ 200 及 301 ~ 400 的報文段被重傳了。
結論:
透過選擇確認在報文段丟失的時候,如果說觸發的是快速重傳的話,當收到三個相同的確認報文段後,即可重傳那些被丟失的報文段,而不必為每個丟失的報文段需要接收三個相同的確認報文段才能進行重傳;如果說觸發的是超時重傳的話,接收方不需要丟棄未按序到達且已經接收的報文段,而是保留然後告知發送方你應該重傳哪些報文段給我。
累積確認
試想一下,在傳輸過程中報文段會丟失,那麼確認應答報文段會丟失嗎?當然是會的,所以為了避免確認應答報文段的丟失而引起的不必要重傳,進而造成網路的負荷增大,於是 TCP 採用了累積確認來解決。以下我們以圖來說明:
如左圖,可以看到第一個報文段的確認應答報文段在傳輸過程中丟失了,接著 A 發送出第二個報文段,B 接收到之後對 A 發送了一個確認應答報文段,此時 A 接收到此應答報文段(這是在第一個報文段的超時重傳時間內接收到的),它累積了前面已經接收到的序列號了,所以說第一個報文段不需要被重傳,以節省不必要的網路浪費。
一個累積確認的通俗解釋
無論丟失了多少接收方返回的確認應答報文段,只要在超時重傳時間內成功接收到一串應答中的最後一個確認報文段(累積了前面已接收到的序列號),那麼就不必要重傳已經接收到的報文段,可以節省整個網路的負荷。
連接管理
TCP 建立連接(三次握手)
現在有兩個端系統要基於 TCP 進行通信,其中一端系統的某個應用行程主動發起連接建立,我們稱這為 TCP 客戶端,另一個端系統的應用行程被動等待連接建立,我們稱這為 TCP 伺服端。
如上圖所示,以下將說明:「通過三次握手建立 TCP 連接的過程」
- 一開始客戶端與伺服端都處於 CLOSED 狀態。伺服端會先進入 LISTEN 狀態,等待來自客戶端的連接請求。
- 客戶端向伺服端發起連接請求,此時客戶端向伺服端發出 SYN 報文段(TCP 連接請求報文段),該報文段首部的 SYN 欄位被設置為 1,同時選擇一個初始序列號 seq = x(SYN 報文段是不能攜帶資料的,但是要消耗一個序列號),發送完後,客戶端進入 SYN - SENT 狀態。
- 伺服端收到客戶端的連接請求報文段後,如果同意連接就會向客戶端發出 TCP 連接請求確認報文段,並且伺服端進入 SYN - RCVD 狀態。這個連接請求確認報文段首部中的 SYN、ACK 欄位被設置為 1,確認號 ack = x + 1,同時選擇一個初始序列號 seq = y(伺服端所選的初始序號),一樣的這個 TCP 連接請求確認報文段是不能攜帶資料的,但是要消耗一個序列號,因為其 SYN 欄位也是被設置為 1。
- 客戶端收到伺服端的連接請求確認報文段後,還要向伺服端發送一個普通的確認報文段(可以攜帶資料),然後進入 ESTABLISHED 狀態。
- 伺服端收到客戶端的確認報文段後,也進入 ESTABLISHED 狀態。
§ 三次握手的必要性
三個原因
- 三次握手才能防止歷史連接(主因)
- 三次握手才能同步雙方的初始序列號
- 三次握手可以避免資源的浪費
(1)防止歷史連接
以下我們針對三次握手及兩次握手來探討它們之間的差異,為什麼三次握手可以防止歷史連接呢?而兩次卻不能呢?
如上圖所示,以下將說明:「為什麼通過三次握手可以防止歷史連接」
- 舊的 SYN 連接請求報文段在網路傳輸中延遲了,計時器到時後觸發超時重傳,此時發送一個新的 SYN 連接請求報文段。
- 舊的 SYN 連接請求報文段比新的 SYN 連接請求報文段還要早抵達伺服端,此時伺服端收到舊的 SYN 連接請求報文段後,向客戶端發出 SYN 連接請求確認報文段,然後進入 SYN - RCVD 狀態,此時伺服端還不能發送資料,客戶端收到的不是期望的 ack,所以客戶端發起 RST 報文段終止連接。
- 新的 SYN 連接請求報文段抵達伺服端被接收後,此時伺服端向客戶端發出 SYN 連接請求確認報文段,然後進入 SYN - RCVD 狀態,客戶端收到期望的 ack 後,向伺服端發出普通的確認報文段然後進入 ESTABLISHED 狀態。
- 伺服端收到普通的確認報文段後,進入 ESTABLISHED 狀態。
- 這裡點出重點來,發送 SYN 連接請求報文段的客戶端會進入 SYN - SENT 狀態而發送 SYN 連接請求確認報文段的伺服端會進入 SYN -RCVD 狀態,也就是還沒進入 ESTABLISHED 狀態,所以還不能進行資料傳輸,自然而然就能防止歷史連接。
如上圖所示,以下將說明:「為什麼通過兩次握手不能防止歷史連接」
- 舊的 SYN 連接請求報文段在網路傳輸中延遲了,計時器到時後觸發超時重傳,此時發送一個新的 SYN 連接請求報文段。
- 舊的 SYN 連接請求報文段比新的 SYN 連接請求報文段還要早抵達伺服端,此時伺服端收到舊的 SYN 連接請求報文段後,向客戶端發出 SYN 連接請求確認報文段,然後進入 ESTABLISHED 狀態,此時伺服端可以發送資料。
- 客戶端接收到 SYN 連接請求確認報文段後,發現 ack 不是期望的,所以向伺服端發起 RST 報文段終止連接。
- 伺服端收到 RST 報文段後將此歷史連接終止。
- 此時伺服端收到新的 SYN 連接請求報文段,然後向客戶端發送 SYN 連接請求確認報文段後,進入 ESTABLISHED 狀態。
- 客戶端收到 SYN 連接請求確認報文段後,也進入 ESTABLISHED 狀態。
結論:
從以上可以看出三次握手與兩次握手的差別,三次握手多了 SYN - SENT 及 SYN - RCVD 狀態,這兩狀態可以有效地預防建立一個歷史連接,避免資源的浪費,而兩次握手卻是直接進入 ESTABLISHED 狀態,從而導致建立了一個歷史連接。
(2)同步雙方初始序列號
前面在可靠性傳輸的一些原理有提到序列號的作用,以下將再次提及序列號的功用:
- 使接收方可以明確地知道自己已經接收哪些資料了,並且如果有資料的丟失也可以告知發送方我缺哪些資料。
- 使接收方可以知道哪些是重複的資料,並且將其丟棄。
(3)避免資源浪費
如上圖所示,以下將說明:「兩次握手造成的資源浪費」
- 一開始客戶端發送一個 SYN 連接請求報文段,但它可能在網路中滯留了,於是觸發超時重傳,重新發送一個新的 SYN 連接請求報文段。
- 客戶端與伺服端經歷了一個完整的建立連接及釋放連接週期後,在網路當中滯留的 SYN 連接請求報文段抵達伺服端,伺服端接收後向客戶端發起 SYN 確認請求連接報文段,然後進入 ESTABLISHED 狀態。
- SYN 確認請求連接報文段抵達客戶端後,客戶端對其不理睬,此時的伺服端就一直等待客戶端發送資料過來,造成了伺服端的資源浪費。
結論:
應該確保一問一答也就是說發送出 SYN 報文段,也要收到 ACK 確認報文段才能進入 ESTABLISHED 狀態,從而避免不必要的連接建立。
TCP 斷開連接
如上圖所示,以下將說明:「通過四次揮手釋放 TCP 連接的過程」
- 現在客戶端打算關閉連接,此時會向伺服端發送一個連接釋放報文段,並且進入 FIN - WAIT - 1 狀態。此報文段首部 FIN、ACK 欄位皆被設置為 1(表示此報文段是連接釋放報文段,同時也是對之前收到的報文段進行確認的報文段),序列號 seq = u(為客戶端之前已經傳送的報文段資料的最後一個位元組序列號 + 1),確認號 ack = v(客戶端之前已收到的報文段資料的最後一個位元組序列號 + 1)。FIN = 1 的報文段不攜帶資料,但是要消耗一個序列號。
- 伺服端收到連接釋放報文段之後,會向客戶端發送一個普通的確認報文段,並且進入 CLOSE - WAIT 狀態。
- 客戶端收到確認報文段後,就進入 FIN - WAIT - 2 狀態,然後等待伺服端發出的 TCP 連接釋放報文段。
- 伺服端剩餘資料傳輸完畢之後,就會向客戶端發送一個連接釋放報文段後,就進入 LAST - ACK 狀態。
- 客戶端收到連接釋放報文段之後,會向伺服端發送一個普通的確認報文段,並且進入 TIME - WAIT 狀態。
- 伺服端收到確認報文段後,就會進入 CLOSE 狀態,至此伺服端已經完成連接關閉。
- 然客戶端在經過 2MSL 一段時間後,就會進入 CLOSE 狀態,至此客戶端也完成連接關閉。
滑動窗口(Sliding - Window)
為什麼要引入滑動窗口呢?
滑動窗口實現了對發送 TCP 串流進行控制,也就是說要限制這些即將被傳輸的串流資料在一個一定範圍裡假定為 N(這不是一定值,而是由接收窗口及擁塞窗口決定),為什麼呢?在後面的章節中會提及流量控制及擁塞控制這些就是它的原因之一,同時也解決過往的一問一答的傳輸方式,可以大量的發送資料,而無需等待每個資料的確認應答,進而提高網路通信效率。
§ 發送窗口可視化
- 發送窗口:僅有在窗口裡面的資料皆可以被發送,同時可以連續發送,無需等待確認應答。
- 可用窗口:可以被發送的資料數量,但是還未被發送。
§ 滑動窗口
引入滑動窗口與沒有引入的差別
(1)一問一答
如下圖所示當 A 發送報文段給 B 後,A 必須要等到 B 的確認應答才能再繼續往下發送資料。這樣為每個報文段進行確認應答,才能再繼續往下發送報文段的行為,如果報文段的往返時間越長,就會導致網路的吞吐量越低。
(2)滑動窗口方式
如下圖所示 A 不需要等到 B 返回的確認報文段,即可連續發送多個報文段,這樣解決了必須等待大量時間進行傳輸,從而提高網路的吞吐量,也就是說傳輸資料變快了。
流量控制(flow-control)
TCP 流量控制原因及概念
作用於接收方緩存區,主要是要消除發送方使接收方緩存溢出的可能性,以下會以幾個面向進行討論,如下列表:
- 為什麼要進行流量控制呢?
- 流量控制是如何運作的?
§ 流量控制原因
如上圖所示,以下將說明:「沒有對發送方進行流量控制的情形」
從上圖可以看出,A 發送資料速度過快,超過了 B 從接收緩存讀取的速度,引起了 B 接收緩存溢位進而丟棄報文段,A 也因此必須重傳這些被丟棄的報文段,這無疑是增加了網路負荷,所以才要對 A 發送速率進行控制,讓 B 可以來得及處理。
§ 流量控制的運作
主要是利用滑動窗口機制來實現流量控制的,在通信過程中接收方根據自己的緩存空間大小,動態地調整發送方的窗口大小,也就是告知我現在的接收窗口 rwnd 是多少,那發送方就可以知道我現在可以發送多少資料給接收方了。
發送窗口與接收窗口的關係
- 發送窗口:swnd,接收窗口:rwnd
- 不考慮擁塞控制
流量控制方法
如上圖所示,以下將說明:「接收方對發送方進行流量控制的方法」
- 基於滑動窗口機制,可以方便地使 TCP 連接實現對發送方的流量控制。
- 不考慮擁塞控制,僅以流量控制分析
- 發送方送出 1 ~ 300 的資料,其中 201 ~ 300 丟失了,接收方收到了 1 ~ 200 的資料,並且回傳確認報文段(ACK = 1,ack = 201,rwnd = 300),這個確認報文段通知了發送方,我(接收方)目前的接收窗口是 rwnd = 300,並且確認已經收到 201 以前的資料了,此時發送窗口向前移,並調整發送窗口為 300,把已經確認的資料從緩存中清除。
- 接著發送方傳送 301 ~ 500 的資料,此時已經達發送窗口的上限了,所以不再繼續發送資料,並且超時重傳計時器的時間到了,所以重新發送剛剛丟失的報文段資料 201 ~ 300,接收方一樣在預定的累積確認時間內對發送方發出一個確認報文段(ACK = 1,ack = 501,rwnd = 0),這個確認報文段通知了發送方,我(接收方)目前的接收窗口是 rwnd = 0,並且確認已經收到 501 前的資料了,此時因為接收方告知接收窗口是 rwnd = 0,所以發送方要調整其發送窗口將其調整為零,所以發送方不能再發送資料了。
- 發送方收到接收方發送的零窗口報文段不久後,接收方的接收緩存此時又有空間了,於是通知發送方我的接收窗口為何,但這個報文段卻在傳輸過程中丟失了,於是雙方彼此互相等待,造成死鎖局面,所以必須有個機制來處理這樣的情況,以下將會介紹這個處理機制。
§ 窗口關閉
剛剛前面有提到雙方互相等待彼此,進而造成死鎖局面,現在我們來討論一下,遇到這種情況的處理機制。
如上圖所示,以下將說明:「接收到零窗口報文段的處理機制」
- 發送方收到零窗口通知,就會啟動持續計時器,此時的發送方無法再發送任何資料了,於是只能等待來自接收方的非零窗口通知。
- 接收方處理完資料後,接收方有空閒的儲存空間了,此時向發送方發送一個非零窗口通知,但是在途中丟失了。
- 由於前面有啟動持續計時器,所以當持續計時器超時的時候,發送方會發送一個攜帶 1 位元組的零窗口探測報文段,這麼做主要是為了要避免死鎖局面。
- 接收方收到零窗口探測報文段後進行確認,然後向發送方通告自己當前的窗口大小。
擁塞控制(congestion control)
TCP 擁塞控制原因及概念
作用於網路,主要是要消除網路擁塞的可能性,這裡會針對幾個面向來討論,如下列表:
- 說明擁塞原因及 TCP 為何要進行擁塞控制。
- 採用的是哪種模式來得知網路的擁塞。
- 流量控制與擁塞控制有什麼不同呢?
§ 擁塞原因
計算機網路中的所有資源都是有限的,當其對某個資源(路由器、交換機等等)需求超過可用部分時,就會造成網路傳輸性能下降,這就是網路擁塞。
假定我們剛剛所說的資源是路由器好了,它會解析資料所包含的位址,然後將資料轉發到離目的地更近的路由器或直接轉發到目的地,在轉發之前,路由器它必須將所收到的資料先放在其緩存當中,然後才能進行處理及轉發,正如前面所說網路中所有資源都是有限的,所以路由器中的緩存也是有限的,因此它待處理及轉發的資料數量是有限的,資料過多就會引起緩存溢出丟棄後來的資料,這直接地影響其他路由器,讓轉發給該路由器資料的路由器都做白工了。
§ TCP 為何要進行擁塞控制?
TCP 是具有重傳機制的協議,對於這種協議來說,如果網路發生擁塞了,會發生頻繁地重傳資料,無疑會使資料被迫延長時間到達,同時頻繁地重傳會使網路的擁塞加劇,所以當網路發生擁塞時,TCP 會降低其發送的資料量,來解決網路擁塞問題。
TCP 的擁塞控制就是說在傳輸的過程中,網路如果發生擁塞了,那麼會減少向網路發送的資料,以此來調節,而避免使網路阻塞更加嚴重,相反的網路不擁塞時,可以提高資料的發送,最大限度地利用網路資源。
§ 兩種模式的擁塞控制
(1)端到端擁塞控制
在端到端擁塞控制方法中,網路層沒有為傳輸層提供網路擁塞時的通知,而是端系統通過對網路行為的觀察,來判斷網路是否發生了擁塞。是這樣的當傳輸中的報文段丟失了(引起快重傳或者超時重傳),這就是網路擁塞的跡象,也根據此跡象來做出應對的擁塞控制。這是當前 IP 和 TCP 默認的採用的擁塞控制方法。
(2)網路輔助的擁塞控制
從網路中出現擁塞情況的節點(路由器)向發送方提供網路擁塞狀態的反饋信息。IP 和 TCP 也能夠選擇性地實現網路輔助擁塞控制。
§ 有了流量控制為什麼還需要擁塞控制呢?
是這樣的,它們彼此間針對的是不同方面,流量控制是作用於接收方的接收處理能力,針對的是發送方與接收方的速率匹配關係,也就是探討消除發送方使接收方緩存溢出的可能性,而擁塞控制則是作用於網路,針對的是整個交通網路的調節,也就是探討消除網路擁塞的可能性,這很重要雖然兩個概念看似相似,但是別它們兩個混淆了。
發送窗口與擁塞及接收窗口的關係
- 發送窗口:swnd,擁塞窗口:cwnd,接收窗口:rwnd
在前面提過的流量控制我們是不考慮擁塞控制的,也就是說 swnd 與 rwnd 是大約等於的關係,現在加入了擁塞控制的概念後,swnd 的值也會受到 cwnd 的影響,如下:
擁塞控制算法基本概念
§ 慢啟動
當一個 TCP 連接建立完成後,開始可以傳輸資料時,TCP 會使用慢啟動算法進行流量控制,最初會將流量大小設置為一個很小的值,然後隨著傳輸成功的報文段不斷增加,這流量大小也會被快速地增加。
特性
- 慢啟動指的是一開始啟動時,被發送至網路的報文段是以少量為主,並非是慢慢啟動,其被發送至網路的報文段隨後呈倍數增加(每個輪次的報文段數量)。
- 發送方每收到一個 ACK,擁塞窗口 cwnd 就會加 1。
如上圖所示,以下將說明:「慢啟動算法的變化過程」
- TCP 連接建立完成後,擁塞窗口 cwnd 的值被設置為 1,表示一開始只可以傳送一個 MSS 大小的資料。
- 現在發送方收到一個 ACK 確認報文段後,擁塞窗口 cwnd 的值加 1,此時的擁塞窗口 cwnd = 2。
- 因為擁塞窗口 cwnd = 2,所以現在發送方可以發送兩個報文段,接收方收到這兩個報文段後,會傳回各自的 ACK 確認報文段,當發送方收到這兩個 ACK 確認報文段,擁塞窗口 cwnd 的值加 2(此時 cwnd = 4),於是現在發送方可以發送 4 個報文段了。
- 發送方現在可以向接收方發送 4 個報文段,接收方收到 4 個報文段後,緊接著回傳各自的 ACK 確認報文段給發送方,發送方收到這 4 個 ACK 確認報文段後,擁塞窗口 cwnd 的值加 4(此時 cwnd = 8),於是現在發送方可以發送 8 個報文段了。
- 當然擁塞窗口 cwnd 不是一直呈指數增加的,當超過慢啟動門限 ssthresh 後,就會進入到擁塞避免算法,以下小節將會討論。
§ 擁塞避免
慢啟動算法執行一定時間後,擁塞窗口 cwnd 的值會增長到一定程度,當其超過慢啟動門限 ssthresh 的值,就會轉而執行擁塞避免算法,以避免網路過度擁塞。
特性
- 每當收到一個 ACK 確認報文段,擁塞窗口 cwnd 就會增加 1/cwnd。
- 每個輪次僅增加一個報文段的傳輸數量。
如上圖所示,以下將說明:「擁塞避免算法的變化過程」
- 前面有說到慢啟動門限 ssthresh = 8,所以現在擁塞窗口 cwnd = 8,就會停止慢啟動算法,轉而執行擁塞避免算法。
- 發送方現在可以向接收方發送 8 個報文段了,此時發送方每收到接收方傳來的確認報文段都僅僅增加 1/cwnd,也就是說每個輪次 cwnd 只加 1。
§ 快速重傳與快速恢復
快速重傳與快速恢復通常同時使用,當發送方在超時時間內還能收到三個重複的 ACK 確認報文段,表示當前網路並沒有那麼擁塞,只是某些原因丟失了報文段,於是啟動快速恢復算法。
特性
(1)進入快速恢復算法
- 慢啟動門限 ssthresh=cwnd/2
- 擁塞窗口 cwnd=ssthresh+3(3 表示有收到 3 個確認報文段)
(2)回到擁塞避免算法
如上圖所示,以下將說明:「快速恢復算法的變化過程」
- 收到三個重複的 ACK 然後進入快速恢復狀態,此時的慢啟動門限 ssthresh=cwnd/2,擁塞窗口 cwnd=ssthresh+3。
- 在此期間如果發送方有收到重複的 ACK 確認報文段,其擁塞窗口 cwnd 都要加 1,直到收到新的 ACK 確認報文段。
- 發送方收到新的 ACK 確認報文段後,擁塞窗口 cwnd 被設置為 ssthresh,然後進入擁塞避免算法。
§ 兩種情況的擁塞發生
(1)快速重傳
前面已經介紹過快速重傳及快速恢復了,所以在這裡不多加贅述。
(2)超時重傳
這個擁塞發生是由超時重傳所觸發的,表示傳送給接收方的報文段在網路當中丟失了,這也意味著現在網路可能出現擁塞,所以發送方必須對發送流量採取措施,來避免網路的擁塞。
特性:
- 慢啟動門限 ssthresh 被設置為 cwnd/2。
- 擁塞窗口 cwnd 被設置為 1(假定的,正確來說是恢復成初始化值)。
參考來源
- B站,深入淺出計算機網路微課堂
- James F. Kurose, Keith W.Ross。《計算機網路:自頂向下方法》。陳鳴譯。機械工業出版社。
- 《深入淺出計算機網路》。高軍、陳君、唐秀明及張劍。清華大學出版社。
- 《圖解TCP/IP》