1. 程式人生 > >傳輸層-Transport Layer(下):UDP與TCP報頭解析、TCP滑動視窗、TCP擁塞控制詳解

傳輸層-Transport Layer(下):UDP與TCP報頭解析、TCP滑動視窗、TCP擁塞控制詳解

# 第六章 傳輸層-Transport Layer(下) 上一篇文章對傳輸層的定址方式、功能、以及流量控制方法做了簡短的介紹,這一部分將介紹傳輸層最重要的兩個例項:TCP協議和UDP協議,看一看之前描述的傳輸層要素是如何應用於TCP、UDP協議之中,並實現他們各自特點的。這一章中,讀者應該重點關注TCP與UDP的區別,以及TCP是如何實現滑動視窗、擁塞控制的。 # 6.4 Internet傳輸協議:UDP/User Datagram Protocol ## 6.4.1UDP特點 ![](https://img2020.cnblogs.com/blog/2183510/202012/2183510-20201211194522640-552627360.png) 上圖是UDP的頭。UDP的頭很短,只包含源和目標埠號、長度和校驗和四個項。 - **UDP是一種無流控、無連線、不可靠的報文流(對比TCP)** - **目標埠號一共有16位長,用於區分不同程序** - **UDP沒有包括流量控制、擁塞控制或者是重傳機制。所有的這些都需要使用者程序自己完成。而UDP本身只是提供了一個與IP協議的介面。** - UDP偽頭:是一個虛擬的資料結構,不是UDP頭中的實際部分。偽頭的存在主要是為了計算校驗和,保證到達的UDP包確實是傳送給自己的(因為UDP頭中只含有埠資訊,並沒有IP地址)。這麼做的原因詳見6.6Faq。**TCP和UDP都有偽頭** 下面介紹兩個使用了UDP的經典協議。 ## 6.4.2 遠端過程呼叫:Remote Produce Call - 允許一臺計算機上的程序呼叫另外一臺計算機上的程序 - 是一個分散式C-S系統的例子 ## 6.4.3 實時傳輸協議: Realtime Transport Protocol - 應用於多媒體應用,如網路電臺、視訊會議RTP的頭設有一個序號(Sequence Number)欄位,解決了UDP傳送無序的問題 - **RTP位於應用層**,但是使用了UDP的傳輸協議 # 6.5 Internet傳輸協議:TCP/ Transport Control Protocol(重要!) 終於到了本章最後一個也是最重要的部分:TCP協議。我們之前已經簡述了三次握手、AIMD等基本概念,下面將深入的展開這些概念,並明白他們是如可確保TCP連線可靠性的。 - **TCP是一種*可靠的
*、*面向連線*的*端對端的位元組流(Bytestream)*(對比UDP)** ## 6.5.1 TCP服務型別 - **TCP連線是全雙工的、不支援組播或者廣播** - **TCP的連線是位元組流,意味著不保留訊息的邊界** ## 6.5.2 TCP報頭(head) ![點選檢視源網頁](https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=3131114988,4182504741&fm=26&gp=0.jpg) 注意關注TCP報頭的以下幾個欄位: - 序號sequence number:用來進行排序,保證資料內容有序 - 序號+確認號:**為TCP滑動視窗服務**(稍後會提到) - TCP頭長度TCP header length:標記TCP頭具有多少個32位資訊,以區分報頭和載荷(由於TCP頭有兩個位置是可選長度,故不確定長度) - 校驗和CheckSum:用於差錯控制,保證可靠性,**也有IP偽頭**。 - 8位標誌位:SYN用於建立連線;ACK是確認;FIN是釋放連線;CWR與ECE用於擁塞控制 - 視窗大小:**用於流量控制(滑動視窗)** ## 6.5.3 TCP連線建立 TCP連線建立使用的即是我們之前描述的**“三次握手”**的過程。注意明確兩個主機之前各自的SEQ和ACK序號是怎麼確定的。 ![](https://img2020.cnblogs.com/blog/2183510/202012/2183510-20201211195156608-1197185691.png) ## 6.5.4 TCP連線釋放 **TCP的連線釋放屬於對稱釋放,記成“四次握手”** 由主機1傳送一個斷開連線請求,表示內容已經傳送完畢,主機2確認。主機2隨後也傳送一個斷開連線請求,主機1確認後連線正式斷開。 ## 6.5.5 TCP滑動視窗 我們在之前已經講過了鏈路層的滑動視窗。而在傳輸層,TCP的滑動視窗是依靠TCP報頭中的序號欄位和確認號欄位實現的。通過滑動視窗,TCP可以合理的調整發送的流量,減少擁塞現象的發生。下面用圖片來解釋。 假設接收方擁有一個大小為4kb的緩衝區。傳輸層每次接收到訊息之後就會發送至這個緩衝區,同時系統也會以另一個速率從緩衝區讀取資訊。流量控制的目的就是維持一個合適的速率使得整個緩衝區既不溢位也不會浪費資源。此時連線已經建立,由傳送方先開始傳送資料。每次收到資料後,發回的ACK都包含一個欄位提示自己的緩衝區餘量。如果緩衝區已滿,傳送端就會將自己阻塞一段時間。 ![](https://img2020.cnblogs.com/blog/2183510/202012/2183510-20201211195224371-1970056373.png) 這裡需要特別注意的還是ACK與SEQ欄位大小該如何設定。**SEQ欄位只屬於傳送端,其含義大概可以理解為“已經發送了多少資料”,因此其大小等於上一個資料包中收到的ACK大小;而ACK表示的是“已經接受了多少資料”,其大小等於上一個傳送端發來的資料包序列號+本次收到的資料大小。** **此外,降低TCP效能的另一個原因是低能視窗綜合症**。當接收端每次只能讀取很少的位元組(假如在上面這個例子中,接收方每次剛剛讀取了0.5k之後就通知傳送方),整個系統會產生大量的冗餘資訊。**解決的方法是強制接收方在有了一定大小的空間之後再通知對方。** ## 6.5.6 TCP計時器管理 這一部分的內容主要是關於如何設定一個合適的時間界限判斷資料包是否應該由於超時而被丟棄。 ![](https://img2020.cnblogs.com/blog/2183510/202012/2183510-20201211195302830-1969121215.png) 通過上圖我們可以看到,再資料鏈路層中(左圖),資料包到達的時間的概率密度函式相對比較集中,因此很容易設定一個界限來判斷是否超時;但是在網路層下資料包到達的時間則更加分散,很難設定一個判斷標準。解決的方法是**使用一個依據網路情況的動態演算法。** ## 6.5.7 TCP擁塞控制(重要!) 首先簡短回憶一下:網路層檢測到擁塞後,會通過丟棄資料包來緩解擁塞。在傳輸層,我們可以使用AIMD控制法來優化網路容量。TCP的擁塞控制就以AIMD為基礎,並加以改進。 #### **擁塞視窗** **TCP維護了一個擁塞控制視窗CWND-congestion window,視窗大小是任意時刻,傳送端可以向網路傳送的位元組數。通過使用視窗大小/連線的往返時間,可以得到傳送速率。TCP根據AIMD規則調整CWND大小。除此之外,TCP本來就有一個流量控制視窗RWND,指出了接收端可以接受的最大位元組數,TCP最終的可能傳送位元組數就是兩個視窗中的最小值。** 相比起存放在報頭中的RWND,CWND視窗維持在傳送端本地,不會隨著資料包傳送。 #### **確認時鐘** 確認時鐘作用在之前講道德CWND上,其目的是提供一個可靠的傳送速率。根據觀察,人們得出:確認返回到傳送端的速率恰好是資料包通過路徑上最慢鏈路的速率,這個時序就是確認時鐘。**通過使用確認時鐘,資料包不會擁塞鏈路上的任意一個路由器,使得TCP能夠平滑輸出流量並且避免不必要的路由器佇列。** #### **慢速啟動-slow start** 之後的幾個問題研究的是如何維持一個合適的CWND。儘管AIMD規則提供了一個比較好的思路,但是**假如CWND從一個很小的規模就開始應用AIMD,則需要很長的時間才能收斂至最優點。**人們因此提出了**快速啟動**的觀點:**每一個被確認的段允許傳送兩個段,每經過一個往返時間,擁塞視窗增加一倍。** ![](https://img2020.cnblogs.com/blog/2183510/202012/2183510-20201211195341948-1523905530.png) 圖中,RTT表示往返時間。如果資料包在一個往返時間內收到,那麼表示當前的網路狀況為通暢。**慢速啟動方式其實並不慢,CWND視窗的增長是指數級的。**但相比之前的做法(直接傳送RWND視窗大小的資料作為開始點),慢速啟動又相對的慢一些。此外,還有必要為慢速啟動設定一個**慢速啟動閾值**,**一旦超出了閾值,TCP就會從慢速啟動切換到線性增加-additive increase(也就是我們在AIMD中學到的知識)**。在每一個RTT末尾,傳送端額外注入一個數據包。 ![](https://img2020.cnblogs.com/blog/2183510/202012/2183510-20201211195414832-148526899.png) #### **快速重傳-fast retransmission** 慢速啟動的缺陷是必須設定一個更加保守的超時判斷時間來防止因重複資料包太多導致的網路擁塞,因此可能會降低網路效率。使用**重複確認(duplicate ack)**機制可以部分解決這個問題:當丟失資料包的後續資料包到達接收端時,他們所觸發的返回確認全部擁有相同的確認號。當傳送方收到多個確認號相同的資料包後,那麼就可以推斷出某個資料包已經丟失(或者至少是超時)。 在TCP中,這個重複確認的數量通常被設定成3。當收到了三個連續的重複確認,傳送端預設這個包已經超時,直接重新發送這個資料包(在判斷超時的計時器結束之前),這麼一來就縮短了等待時間。**這種方法叫做快速重傳。當重新發送之後,傳送端會把自己的CWND閾值設定為之前CWND值的一半,並從0開始慢速啟動。** ![](https://img2020.cnblogs.com/blog/2183510/202012/2183510-20201211195440592-339441767.png) 如上圖,慢速啟動的第一個閾值被設定成32KB,並在CWND=40時發生丟包現象。丟包被檢測到之後,確認時鐘停止;新的閾值被設定為**40KB 的一半-->
20KB;重新從0開始,執行慢速啟動。**這是一種**階梯狀**的模式。 #### **快速恢復-fast recovery** 快速恢復是一種新的機制,**用於確保擁塞視窗上能夠持續執行確認時鐘。**也就是說,**除非是第一次啟動,其他時候不會進入慢速啟動,而是直接從閾值開始線性遞增。**這是一種**鋸齒狀**的模式。 ![](https://img2020.cnblogs.com/blog/2183510/202012/2183510-20201211195458534-686558715.png) 現在重新觀察TCP擁塞控制的這張圖片不難發現,其實線性遞增部分就是對應著上一篇博文AIMD中的加法遞增部分,而快速恢復機制對應了AIMD中的乘法遞減部分(乘以1/2)。只不過上一篇中的AIMD影象表現的是兩個傳送端的流量變化關係,而上圖表現的是一個客戶端的流量隨著時間的變化關係(時間是橫座標)。 # 6.6 TCP與UDP區別比較 | TCP | UDP | | ------------------------------------------------------------ | ------------------------------------------------------------ | | TCP面向連線,提供可靠的服務。
意味著TCP會使用校驗和確保資料正確,使用序號確保資料有序到達且不重複,使用ACK機制重新發送丟失的資料包,並且包含連線建立和斷開的過程。 | UDP提供的是無連線的服務,並不可靠。
UDP不包含序號和ACK重傳等機制。(當然,當應用層擁有一些特殊需求時,UDP也可以調整自己的格式以提供一些特殊服務,例如實時傳輸協議RTP) | | TCP具有擁塞控制的功能,使用改進的AIMD規則來減少擁塞 | UDP沒有擁塞控制,當網路層出現擁塞時,也不會使得源主機的傳送速率降低。 | | TCP連線只支援單播,一定是點到點的。 | UDP可以進行單播、多播、廣播。 | | TCP使用位元組流,不保留訊息邊界。當資料過大的時候會進行拆分。 | UDP面向報文流,會保留應用層提供的訊息邊界。 | | TCP的首部更長,傳輸速度相對較慢 | UDP的首部較短,傳輸速度也更快。 | 另外關於報文流和位元組流,下圖可以更方便理解。 ![](https://img2020.cnblogs.com/blog/2183510/202012/2183510-20201211195533785-229138182.png) 假如應用層提供了一個2048位元組大小的資料等待發送,TCP可能會將其拆分成4個512位元組大小的資料段,分別傳送給網路層,接收方再負責組合。真正傳送的資料包並不是應用層的資料,因此稱為沒有保留訊息邊界。 再來看另外一個例子,當客戶分別發出32B和64B的包,流式的如TCP傳送時是將32B+64B=96B的一個包發出,另一邊收到的也是96B的包,TCP不再保留原來資料包的邊界,而是根據協議的需求將資料統一發送;而對於UDP來說,伺服器端收到的就是32B和64B的兩個包,保留了從前資料包的邊界。當然,包大小取決於協議和網路。 # 6.7 FAQ 常見問題 #### 為什麼要區分網路層和傳輸層? 的確,傳輸層和網路層有諸多的相似之處,並且共同負責了包括擁塞控制在內的多個問題的解決。但是分出兩個層次依舊是必要的。 一般情況下來說,傳輸層的程式碼都執行在使用者的機器上,如PC機,或者伺服器;而網路層的程式碼大部分部署在由運營商操作的路由器上。這樣的差別是設計區分這兩個層次的主要原因:使用者對網路層並沒有真正的控制權,因為他們不擁有路由器;而另一方面,路由器也沒有許可權在資料包發生丟失等情況後要求PC機重新發送這個資料包。 #### UDP和TCP為什麼需要偽頭(pseudoheader)? 偽頭存在的目的是為了幫助傳輸層的程序再一次確認該資料包確實屬於這個程序所在的ip地址。問題在於,為什麼傳輸層還需要再做一遍網路層的工作呢?難道到達網路層的時候不是已經校驗過IP地址的準確性了嗎?理論上來講確實是這樣的。然而在實際應用中確實會發生錯發的現象,網路層可能會把一個數據包發至錯誤位置。例如路由出錯,或者是資料包的ip頭被修改了(前一章中的NAT盒子就可能會引起這一點)。 #### 傳輸層的校驗和與鏈路層的校驗和有什麼關係? 沒有什麼關係。傳輸層的內容會被一路封裝下去,成為鏈路層的載荷之一。而校驗和是存在各自的頭部,用於校驗某一層的資料是否正確。比如連鏈路層的校驗和只管鏈路層。當然這兩層可能採取了同一種演算法。 #### TCP和TCP/IP有什麼不可告人的關係? 我們在第一章學習了TCP/IP。TCP/IP是一個協議簇(彼此相互關聯的一組協議),包含了STMP、TCP、UDP、IP等等經典協議。因為其中的TCP和IP協議最具代表性,因此統稱為TCP/IP。TCP/IP包含了四個層次的協議。 ****** 到此為止,本章的內容已經全部結束,在下一章中,我們將學習應用層的內容。 第七章