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