TCP 傳輸、重傳及工作原理
IP和MAC層的內(nèi)存受限,用于發(fā)送數(shù)據(jù)包。因此,它們都會限制消息的長度。
這一限制要求TCP在提供給IP層之前,將可變長度的字節(jié)打包成多個段。每個段的長度應該是合適的。
下面是一個簡單的圖示,展示了段是如何通過互聯(lián)網(wǎng)發(fā)送的。
1*IRdfZ4LKKpQ-KRz_Y3QR7g.png
客戶端的HTTP層正在向目標服務器發(fā)送一個18字節(jié)的流。
當字節(jié)16-18尚未到達TCP層時,字節(jié)12-15通過了它。TCP將它們打包成一個段,并附加了一個TCP頭,標記在黃色區(qū)域。
接下來,該段被IP層封裝,通過互聯(lián)網(wǎng)發(fā)送,然后到達服務器。
假設TCP段的長度超過了底層支持的長度。在這種情況下,IP層將負責將大段拆分成多個片段。這是一個昂貴的過程,因此我們希望避免這種情況。
但是TCP如何確定長度呢?這取決于最大段大小(MSS)。
理想情況下,我們希望選擇一個最大化數(shù)據(jù)量、最小化頭部比例并避免在IP層進一步拆分的MSS。
默認情況下,MSS為536字節(jié)。這個數(shù)字是從哪里來的呢?
- IP的默認最大傳輸單元(MTU)為576字節(jié)。超過此大小的任何內(nèi)容都將被拆分。
- IP頭占用20字節(jié)。
- TCP頭占用20字節(jié)。
因此,536 = 576 - 20 - 20。
你可以看出MSS僅表示數(shù)據(jù)體的大小,不包括頭部。
1*creWLybyfKDBJgTzQP1kDg.png
MSS是在TCP三次握手期間進行協(xié)商的。以下是TCP段頭的格式。MSS位于TCP選項中。
1*pQpFRUuyzaG4JOm93Wg5Zw.png
在SYN消息中,客戶端建議MSS為1460字節(jié)。這被稱為發(fā)送方最大段大小(SMSS)。
1*dG1cCAjKY0v8Xfx2SeBcFA.png
在服務器的響應中,它建議段的大小不超過1400字節(jié)。由于大小來自服務器,因此被稱為接收方最大段大小(RMSS)。
TCP 重傳
為了確保傳輸?shù)目煽啃裕琓CP需要完成兩個功能:
- 當接收到消息時,接收方向發(fā)送方發(fā)送確認(ACK)。
- 當消息丟失時,發(fā)送方重新傳輸消息。
讓我們從一個簡單的模型開始。
1*bvkdWnFF55OCLfstaE_GEw.png
1.首先,發(fā)送方在發(fā)送消息后維護一個計時器。2.在時間過期之前收到第一個ACK。然后,計時器被重置以等待第二條消息,然后重復此過程。3.第二個計時器過期,沒有收到ACK。重傳開始。
這種簡單的設計是直接的,但效率較低,因為每個消息都需要等待前一個ACK返回。
讓我們改進一下。
1*suv0nuvpmgUWaTd6riMUsQ.png
通過為每條消息分配一個ID,我們可以迅速發(fā)送多條消息。相同的ID與相應的計時器和ACK消息相鏈接。
如果一條消息丟失,例如#3,發(fā)送方將重新傳輸它。
在TCP中,“消息ID”是什么?它是序列號。
1*EbU2NjtCGn8z4gVCJr2Tyg.png
這里是一個消息的示例:
- 此TCP段的長度為647字節(jié)。
- 在此消息之前,發(fā)送方已經(jīng)發(fā)送了1461字節(jié)。
- 發(fā)送方將從2108開始發(fā)送更多字節(jié)。
序列號最多可以達到232。然后它會重新開始。
這帶來了一個問題。
1*RLp9kmWuRzlgY-NQs2F4Hw.png
想象一下,我們只有4個序列號,每次發(fā)送1字節(jié)。
- 在過程中,第2個字節(jié)(標記為#2)丟失。根據(jù)設計,#2將在以后的時間重新傳輸。
- 我們繼續(xù)發(fā)送更多字節(jié),直到序列號從#1開始。此時,重新傳輸?shù)?2被發(fā)送。
- 接收方不知道這是舊的#2還是新的#2。這可能會搞亂事情。
為了解決這個問題,TCP選項中引入了時間戳。
1*jSrwaU0L-2EHyyIxzb2w_A.png
時間戳可以消除具有相同序列號的段之間的歧義。
讓我們將時間戳附加到每個段上。
接收方讀取時間戳B并將其與先前的時間戳E進行比較,以確認這是一次重傳。否則,時間戳應該大于E。
TCP快速重傳
TCP具有快速重傳功能 - 在計時器到期之前重新傳輸丟失的段。
為了允許快速重傳,我們需要為發(fā)送方和接收方設置一些規(guī)則。
- 規(guī)則1:作為接收方,它應始終發(fā)送它期望接收的序列號。例如,當接收方接收到段1時,它將響應ACK2,表示它期望在即將到來的消息中接收段2。
- 規(guī)則2:作為發(fā)送方,它應忽略計時器并在接收到3個重復的亂序ACK后立即開始重新傳輸丟失的段。
1*nbAE5D9yMkUxvxxR4PJ27g.png
上圖顯示了快速重傳的示例:
- 在第一個2個段的傳輸之后,段3丟失。
- 在接收到段4時,接收方根據(jù)規(guī)則發(fā)送ACK3,而不是ACK4。這是第一個重復的亂序ACK。
- 再次,在接收到段5時,服務器仍然期望重新傳輸段3。因此,第二個重復的ACK3被發(fā)送。
- 然后,第三個重復的ACK3被發(fā)送。
- 在這一刻,發(fā)送方進入快速重傳并重新傳輸段3。6.在接收到丟失的段后,接收方的ACK按順序返回,并期望在即將到來的消息中接收段7。
- 但是存在一個問題 - 發(fā)送方不知道段5和段6是否安全到達,直到快速重傳完成。如果兩個段都丟失,那么后續(xù)的重傳將需要更長的時間。
接收方可以通過選擇性確認(SACK)功能與發(fā)送方共享信息,以便促進重傳過程。
TCP選擇性確認
1*GhT0tOhF3YGrgQOIY56Esw.png
SACK位于TCP選項中。
在SACK中,我們可以指定已經(jīng)接收到的數(shù)據(jù)的范圍,超過確認號。
1*LujjJhnNyITz1dyL-CFfbA.png
這是SACK的示例,表示已接收的數(shù)據(jù)范圍從2872到3393。
有了它,發(fā)送方知道不需要重新傳輸這些邊界之間的任何字節(jié)。
此外,發(fā)送方還可以找出其他丟失的段并盡快進行重傳。
總結(jié)
- 最大段大小(MSS)定義了TCP段的長度。
- 計時器幫助TCP重新傳輸丟失的段。
- 在收到3個重復的ACK后,快速重傳在計時器到期之前開始。
- 選擇性確認(SACK)提供有關(guān)已接收的亂序字節(jié)的信息,以促進快速重傳過程。