TCP/IP学习笔记(四)TCP超时重传及拥塞控制
TCP是可靠的傳輸層協議,但這并不意味著一端發送的數據一定可以到達另一端,因為傳輸過程中遇到的情況是不可控的,很有可能就有某些數據發生丟失,所以”可靠”其實并不可靠。
不過畢竟現如今的網絡設備還算完善,傳輸過程中由于硬件錯誤導致數據丟失的情況基本可以忽略,那么,數據丟失的原因就只能是:傳輸路徑過于擁堵,導致某些路由器或鏈路緩沖區無法再容納多余數據,那么對于新來的數據包就只能丟掉。
為了解決這一問題,保證就算傳輸過程中遇到再多麻煩,也盡量使數據可以順利到達對端,TCP引入擁塞控制用于緩解網絡中的擁堵情況,同時采用超時重傳機制解決數據的丟失問題
超時重傳機制
超時重傳機制主要是為了解決數據包在傳輸過程中丟失的問題,在上一篇關于TCP流量控制的介紹中已經簡單接觸過超時重傳的概念。TCP每發送一個報文段,就會為這個報文段開啟一個定時器,如果定時器溢出時仍然沒有收到接收端的應答報文,那么TCP就認為這個報文段在傳輸過程中丟失,然后重新發送這個報文段。這便是超時重傳機制
以<TCP/IP詳解>中的例子為例,通過tcpdump抓包分析觀察TCP的重傳
首先和遠方的某個服務器進行連接,發送一些數據以確認連接正常,隨后拔掉本機以太網電纜,發送另一條數據
tcpdump的輸出結果為
可以看到,前三行表示TCP的三次握手,四五行分別表示發送的”hello world”報文段以及應答報文段,隨后的若干行表示TCP多次嘗試重新發送”and hi”報文段,最后一行發送復位報文段,終止連接
本質上就是當第一次發送”and hi”報文段時啟動了定時器,然而在規定的時間內沒有收到對端的回復,所以重新發送”and hi”報文段,并重啟定時器(重啟的定時器時間會增大)
擁塞控制
超時重傳是為了解決數據丟失的問題,而數據丟失的原因很大程序上是由于傳輸路徑擁塞導致的。在正常的傳輸過程中,數據是從一個路由器跳到下一個路由器,每個路由器都有自己的緩沖區,新來的數據會存放在緩沖區中,與此同時路由器也在不斷地將緩沖區中的數據發送給下一個路由器。但是如果某個路由器接收數據的速率大于發送數據的速率,就會導致緩沖區數據累積,最終填滿緩沖區。此時如果再有數據到來,緩沖區已經無法容納它們,只能將它們丟掉,造成數據丟失
這就是所謂的擁塞現象,本質就是傳輸路徑上的節點不平衡。為了解決這一問題,就需要當出現擁塞現象時立即減少發送端發送的數據量,為路徑上的某些節點提供清空緩沖區的時間,同時也避免了不必要的重傳。
但是,發送端如何才能得知網絡中發生了擁塞呢。因為由于硬件錯誤造成的數據丟失是很罕見的,所以發送端假定,如果出現了數據丟失,那么就可以認定發生了擁塞。TCP提供了若干緩解擁塞的算法,如
- 慢啟動算法
- 擁塞避免算法
- 快速重傳算法
- 快速恢復算法
下面會分別介紹這幾種算法
由上一篇內容可知,TCP有一個叫做流量控制的機制,它與擁塞控制非常相似,但是仍然有一些差異
- 流量控制是端對端的控制機制,兩端各自通知對方允許的窗口大小以防止對端發送過多數據導致自己來不及處理造成接收緩沖區被填滿
- 擁塞控制不是端對端的控制機制,它是為了緩解從一端到另一端這條路徑上的擁堵問題
不過二者都是通過限制發送方發送的數據包個數來解決問題,所以上述算法無非就是降低發送端發送速率,緩解網絡壓力
慢啟動
慢啟動算法的核心思想是當連接剛建立時允許發送的報文段個數很少,隨后不斷增加允許發送的報文段個數直到規定的閥值
慢啟動為發送方TCP提供了另一個窗口:擁塞窗口,記為cwnd。在對滑動窗口的介紹中得知,發送方滑動窗口不能大于對端允許的窗口大小(稱為通知窗口)。通過通知窗口,發送方可以得知接收方可以接收的數據個數,從而根據這個大小設置自己的滑動窗大小。
有了擁塞窗口的限制,發送方的滑動窗口大小就不能大于擁塞窗口和通知窗口的最小值(多數情況是等于最小值),TCP就會根據這個最小值發送數據。擁塞窗口在連接建立時被初始化為1個報文段,此后每接收到一個應答報文,就將擁塞窗口增加,直到增加到慢啟動閥值
擁塞窗口增加的規則是增加對端接收的報文段數。
比如發送方連續發送兩個報文段,然后兩個應答報文段先后被發給發送方,那么擁塞窗口會先后執行兩次加一。然而如果對端將這兩個應答合并成一個應答報文段發回發送端,由于對端一次應答了兩個報文段,那么擁塞窗口就直接加二
根據應答報文段中對端希望下次接收的序列號和發送端滑動窗口的左邊界序列號,可以計算出對端接收的報文段數。
另外,為了表示方便,擁塞窗口的單位是報文段,一個報文段中可能有多個字節數據。而通知窗口的單位是字節數,也就是序列號數。注意區分
上圖展現了慢啟動算法過程中擁塞窗口大小的變化情況,擁塞窗口初始為1個報文段,所以TCP一次只能發送一個報文段
當TCP將這一個數據發送并得到對端應答后,擁塞窗口加一變為2。此時可以發送兩個報文段,然后接收到其中一個報文段的應答報文段,擁塞窗口加一變為3。此時擁塞窗口為3,由于存在一個已經發送但是沒有收到應答報文段,此時還允許發送兩個報文段,所以接下來TCP連續發送了兩個報文段,如此往復
當然,TCP不能放任擁塞窗口這么瘋長下去,所以設置了一個閥值,當擁塞窗口增長到這個閥值時,慢啟動算法就結束了,隨后會執行擁塞避免算法
擁塞避免算法
擁塞避免算法是當擁塞窗口增長到一定程度時采取的一種算法,該算法的核心思想是減緩擁塞窗口的增加速度,每接收到一個應答就將擁塞窗口加一
注意擁塞避免算法和慢啟動算法對于擁塞窗口的增加是有區別的。當對端將多個應答合并成一個應答報文發送時(由于延遲ACK,通常都會合并發送),慢啟動算法會將擁塞窗口增加多個報文段數而擁塞避免算法只加一個
慢啟動算法和擁塞避免算法通常配合使用,二者需要TCP發送端維護一個擁塞窗口cwnd和一個慢啟動門限ssthresh(閥值),算法工作過程為
- 對一個給定的連接,初始擁塞窗口為1個報文段,同時設置慢啟動門限為65536字節
- TCP輸出例程的輸出不能超過擁塞窗口和通知窗口的大小(二者的最小值是滑動窗口的最大值)
- 執行慢啟動算法,擁塞窗口呈指數增長,當增長到慢啟動門限時改為擁塞避免算法,使得擁塞窗口呈線性加法增長
- 當擁塞發生時,將慢啟動門限ssthresh改為當前窗口的一半,但不能小于2個報文段(當前窗口指的是滑動窗口),然后將擁塞窗口設置為1一個報文段,重新開始慢啟動算法
圖中慢開始指的就是慢啟動算法
由圖片可以看到,當發生擁塞時擁塞窗口立即降為1個報文段大小,使得發送方可以發送的報文段數量急劇下降,這就為傳輸路徑上的節點清空緩沖區提供了時間。此外由于已經發生了擁塞,證明網絡條件并不是很好,所以擁塞窗口要增長的慢些,將慢啟動門限降為一半便是這個目的
快速重傳算法
前面介紹到當數據超時定時器溢出時,發送端便得知有數據丟失,從而認為網絡中發生了擁塞。有什么其他方法可以確定數據丟失呢
考慮這樣一種情況,發送端在發送若干報文段后連續發送了多個報文段[1001:2000],[2001:3000],[3001:4000]…,但是只有后幾個報文段成功到達對端,由于對端希望接收的序列號是1001,所以接收端發送給發送端的所有應答報文段中攜帶的序列號仍然都是1001。
快速重傳算法的核心思想就是當發送端接收到了三個相同的應答報文(攜帶的希望下次接收的序列號相同)時,就假設以該序列號結尾的那個報文段丟失,所以發送端不必等到定時器溢出就會重傳丟失的報文段
快速恢復算法
快速重傳算法僅僅是為了盡早發現丟失報文段并重傳,并不能確定網絡發生擁塞(如果發生嚴重的擁塞,就不會一連有好幾個報文段到達接收端,也就不會一連收到接收端發來的好幾個重復應答報文段),所以不會執行慢啟動算法將擁塞窗口降為1
快速重傳法和快速恢復法的執行過程如下
- 當發送方連續收到三個重復應答報文時,就將慢啟動門限ssthresh減半
- 將擁塞窗口降為減半后的ssthresh值+三個報文段
- 開始執行擁塞避免算法,緩慢增加擁塞窗口
加三個報文段的原因是發送端目前可以確定接收方已經接收到三個報文段(通過接收到三個重復應答報文得知),所以可以確定這三個報文段沒有滯留在傳輸路徑上,也就沒有加重網絡負擔,所以可以加上三個報文段大小
在舊版的快速重傳算法中還是使用慢啟動,但是正如上面所述,網絡很可能沒有發生擁塞,所以在修正后的版本中使用快速恢復算法
重新分組
現考慮一種情況,發送端連續發送M1,M2,M3三個報文段,但只有M1順利到達而M2和M3都在傳輸過程中丟失。如果按正常的流程,發送端TCP會先后重傳M2和M3兩個報文段。
但是從節省報文段數量的角度思考,如果將M2和M3合并成一個新的報文段進行重傳,就能夠減少傳輸過程中的報文段數量,在某種程度上也減輕了網絡負擔
由于TCP數據都是基于序列號的,每個數據都有唯一的序列號,所以可以將兩段數據合成一段
再次使用<TCP/IP詳解>中的例子,示例中首先發送一個報文段確認連接正常,然后斷開以太網電纜并發送兩個報文段(由于網絡連接中斷,這兩個報文段必將重傳),最后插上以太網電纜
觀察tcpdump輸出結果
從圖中可以看到發送”line number 2”報文段時由于網絡原因進行了兩次重傳,隨后鍵入”and 3”嘗試發送,發現TCP將這兩個報文段合并成一個進行發送(從圖中數據個數為20得知)
總結
以上是生活随笔為你收集整理的TCP/IP学习笔记(四)TCP超时重传及拥塞控制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: TCP/IP学习笔记(三)TCP流量控制
- 下一篇: TCP/IP学习笔记(五)TCP的保活定