(轉)為什么收到三個重復的ACK意味着發生擁塞?


三次重復的ACK,可能是丟包引起的,丟包可能是網絡擁塞造成的,也可能是信號失真造成的。

三次重復的ACK,也有可能是亂序引起的,而亂序和網絡擁塞沒有直接關系。

如果就寫這兩行,感覺什么都沒寫,接下來的文字詳細解釋這兩行文字。

TCP背景知識
客戶端有1M的文件需要上傳到服務器上,問題來了,這個大文件能否用一個TCP報文傳輸?

肯定不能啊,因為網絡路徑有最大傳輸單元(MTU = 1500)的限制,所以IP報文不能大於1500字節,那怎么辦啊?

那就讓TCP將1M砍成N個1460字節的segment,這里N=685,問題又來了,這685個TCP報文如果發送方不編號,到達接收方之后,接收方依靠什么方法知道誰是第1個segment,誰是第2個segment。。。誰又是第685個segment?

為何要編號呢?不編號難道不可以嗎?
比如發送方只要將685個segment按序發送, 1、2、3、4、5。。。681、682、683、684、685,這些segment排着隊伍,到達終點順序也應該是1、2、3。。。683、684、685,然后再將685個segment按序拼接在一起,就會復原成1M 字節的文件。

理想很豐滿,現實很骨感,現實會把這個理想擊打成粉粹。現在作者提出三個問題,讀者分析一下如何解決:
(1) 亂序
假如第4、5 segment在傳輸過程中發生了亂序,即5比4先到達,接收方拼接的文件將為“12354。。。”,拼接文件就不是發送方的文件了,而是一個完全沒有意義的廢文件了,拼了老命吭哧吭哧,結果到對方卻是廢文件,這是無法接受的。

(2) 丟包
假如第4個segment在傳輸過程中不幸丟了,接收方無法完整地拼接出原始文件。

(3) 重復包
假如第4個segment在傳輸過程被網絡設備多發送了一次,接收方拼接出的文件將是“123445。。”

如果TCP真是這么脆弱不堪,壓根不會壟斷可靠傳輸層協議,也不會有今天的地位。

那么TCP是如何解決以上三個問題的?

很簡單,就兩個字:編號!

編號可以解決以上三個常見問題,詳細解釋見下文。

亂序
接收方發現5先到,而4沒有到,TCP先將5用倉庫緩存下來,耐心等待4的到來,4到達之后,再按照順序將4、5重寫排列好,這很好理解吧?

丟包
接收方對於接收到的segment,會發送一個確認ACK,告訴發送方已經成功接收的編號數字,對於遲遲沒有確認的segment 4,發送方的鬧鍾(timer)一響(timeout),會自動重傳segment 4,最終接收方也可以收到segment 4。

同學們肯定會說,由於segment 5、6、7沒有丟,可能早就到達了接收方,在segment 4重傳到達之前,TCP如何處理它們?

也是用倉庫臨時堆放一下,等4到來之后,就可以按照4567。。。的順序讓應用程序取走數據了,這個和快遞公司的工作模式很相似。

重復包
既然segment 編號了,接收方發現segment 4已經收到過,再次收到segment 4已經沒有任何意義了,直接丟棄就可以了。

TCP確認機制
發送方發送segment 1,接收方收到之后需要ACK確認,這里需要敲黑板提醒還在睡覺同學的注意,ACK確認號是多少?

ACK = 2 ,什么意思呢? 意思是說,segment 1已經成功接收,寡人等待segment 2的到來。每次寫到這里,都會想起中學語文課本里那句經典名言:讓暴風雨來得更猛烈些吧! 亞當夏娃仍玉米棒子的故事正是受這句名言的啟發。

如果發送方發送的segment是“1、2、3、4、5、6”,那么接收方應該如何ACK確認呢?
同學們會說,那不是很簡單嗎? 收到6個segment,那就發6次ACK,應該是“2、3、4、5、6、7”,當接收方接到ACK =7,就意味着編號7前面所有segment都成功接收,在這里就是“1、2、3、4、5、6”都成功接收了。

問題是ACK的次數有點多,接收方發送一次ACK耗費CPU,接收方接到一次ACK也耗費CPU,另外ACK報文對網絡也是一個小小的負擔。

於是RFC建議優化ACK方法,每收到2個segment,發送一次ACK,這樣就會將ACK數目減半,Good Idea!

那么接收方可以這樣ACK :“3、5、7。。。”,當發送方接收到ACK=7,表明segment 1、2、3、4、5、6已經到了。

問題來了,如果發送方只有一個segment發送,按照以上規則,接收方接收2個segment才發送一個ACK,既然只有一個segment,那接收方的ACK會不會永遠也發不出?

會的,機器是一根筋認死理,這里會造成通信的死鎖(deadlock)。但人是活的,只要幫助TCP啟動一個定時器就好,只要鬧鍾響了(timeout)而第二個segment還沒有到,這時就顧不了那么多,直接發ACK就好。

TCP 慢啟動(slow start)就是先發segment 1,直到接到對方ACK了,才會發segment 2、3。有了這個定時器,就可以避免TCP慢啟動期間的通信死鎖。

信息不對稱
假如發送方發送segment “1234567”,接收方接到的是“1235”,接收方接到5的那一瞬間,知道4有可能丟了,也有可能亂序了,至於是哪種情況,接收方無從知曉。
但發送方對於segment 4的狀態是完全空白的,既然接收方知道多一點,為什么不把這個信息同步給發送方呢?

通過什么方法把消息同步給發送方呢?
ACK =4

有同學會迷惑不解,明明收到的是5,應該ACK= 6,為何這里是4?

ACK=6 是什么意思?

表示 “12345”都成功接收,問題是4收到了嗎?沒有啊!所以只能ACK=4。

稍后,接收方所有接收到的segment為 “12356”,接收方如何做?
ACK=4

再稍后,接收方所有接收到的segment為 “123567”,接收方如何做?
ACK =4

發送方一直記錄自己重復收到某個ACK的次數,Duplicated ACK(4) =3,此時發送方意識到segment 4有可能丟了,此時應該立馬主動將segment 4重傳出去,而不要被動等待segment 4的重傳定時器超時再重傳segment 4。

由於這種依賴外界刺激的重傳方法比超時重傳更快、更及時,美其名曰:快速重傳(Fast Re-transmit)。

當重傳的segment 4到達接收方時,終於將不連續的segment流 “123567” 修復(Restore)成連續的segment流 “1234567”,通常稱這種主動修復字節流的方法為快速修復(Fast Restore)。兩者合在一起統稱Fast Re-transmit / Fast Restore。

上文說的外界刺激,就是發送方連續收到三次duplicated ACK,立馬啟動Fast Re-transmit / Fast Restore機制。

如果上文中的接收方所有接收到的segment 不是“123567”,而是”123564”,此時就是亂序的發生,接收方會重新排序成”123456” ,接收方發送ACK =7即可,segment是連續的,無需修復。

在這種情況下,發送方只接到了兩次duplicated ACK =4,無需啟動Fast Retransmit / Fast Restore機制,因為接收方已經成功修復。

總結一下

沒有Fast Re-transmit / Fast Restore機制,TCP完全可以憑借超時重傳來完成可靠傳輸,由於是被動地等待,所以傳輸效率低下。

FastRe-transmit / Fast Restore機制,使得TCP能夠快速地通過三次重復的ACK,推測報文有丟失的可能,進而主動重傳,傳輸效率更高。

補充閱讀

論修復不連續segment的重要性

上文中的segment 4只要不到達接收方,即使segment 5、6、7。。。早已到達,也只能滯留在接收方的倉庫(Receive Buffer)里,而不能被應用程序取走。

Receive Buffer和Advertised Window Size是直接相關的,接收方的receive buffer被占用,勢必通告給發送方的window size就會變小,影響發送方CWND,進而影響發送方的發送速率。

Delivery Rate = CWND / SRTT

其中

SRTT = Smooth Round Trip Time,平均往返時間延遲

CWND = Congestion Window,發送方擁塞窗口大小,和接收方的Advertised Window Size有直接關聯

Delivery Rate,發送方的發送速率

所以在SRTT不變的前提下,只要CWND變小,發送速率就會下降。

不連續的segment會嚴重影響TCP的傳輸效率。而快速修復這種不連續,會釋放掉占用的倉庫空間,會加快發送方的傳輸效率。
---------------------
作者:牛小可
來源:CSDN
原文:https://blog.csdn.net/niukeming/article/details/80779582
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM