什么是TCP?
基本定義與屬性
- TCP(傳輸控制協議)是傳輸層的重要協議,具有面向連接(傳輸前需先建立連接,是發送方和接收方的點對點一對一連接)、基于字節流(以字節流形式傳輸數據,傳輸中會將字節流組織成不同大小的報文段)、可靠的特性。
核心功能
- 可靠性傳輸:當傳輸大體積數據(如視頻、音頻流)時,TCP 會把數據分成報文段(數據包)依次發送、按序接收。若傳輸中因網絡問題出現丟包,TCP 會通過確認應答、超時重發等機制,保證數據能可靠到達接收方。
- 流量控制:若發送方數據發送速度過快,接收方處理不過來,接收方會通過確認報文告知發送方,讓其減緩發送速度,避免接收方 “過載”。
- 擁塞控制:當網絡中傳輸的數據包過多導致網絡擁塞時,TCP 會通過慢開始、擁塞避免、快重傳、快恢復等手段進行控制,防止網絡擁塞情況加劇。
工作流程(結合圖示)
發送方的應用進程將字節流寫入發送緩存,TCP 為其加上首部構成 TCP 報文段,然后發送該報文段;接收方的 TCP 收到報文段后,從接收緩存讀取字節,再交給應用進程處理,整個過程依托 TCP 連接來保障數據傳輸的有序與可靠。
總的來說,TCP 協議通過一系列機制,為網絡數據傳輸提供了可靠、有序且能適應網絡狀況的服務,是互聯網中保障數據有效傳輸的關鍵協議之一。
TCP協議報文段的格式
TCP 協議報文段是 TCP 協議用于傳輸數據的基本單元,它的格式設計精巧,包含了實現可靠傳輸、流量控制、連接管理等功能所需要的關鍵信息。以下是對 TCP 協議報文段格式的詳細介紹:
整體結構
TCP 報文段由首部和數據部分兩部分組成。首部的前 20 字節是固定的 ,后面有 4N 字節是根據需要而增加的選項(N 是整數),因此 TCP 首部的最小長度是 20 字節。
首部字段詳解
- 源端口號(16 位):標識發送方應用程序使用的端口,占 16 位。通過端口號,可以讓接收方知道數據是由發送方的哪個應用程序發出的,以便接收方將數據正確交付給對應的上層應用進程。例如,瀏覽器訪問網頁時,可能使用一個隨機的大于 1024 的端口號作為源端口與服務器的 80(HTTP)或 443(HTTPS)端口進行通信。
- 目的端口號(16 位):標識接收方應用程序的端口,同樣占 16 位。發送方依據這個端口號,將數據發送到接收方正確的應用程序。如客戶端向服務器發送 HTTP 請求時,目的端口通常是 80 。
源端口號、目的端口號:
就像快遞單上的 “寄件人電話” 和 “收件人電話”。
- 源端口:你(寄件人)聯系電話,告訴快遞站 “誰發的包裹”;
- 目的端口:商家(收件人)聯系電話,告訴快遞站 “包裹該送給誰”。
(比如你用淘寶 App 下單,源端口是你手機淘寶的 “臨時端口”,目的端口是淘寶服務器的 “80/443 端口”)。
- 序號(32 位):用來標識從 TCP 發送端向 TCP 接收端發送的字節流,發送方發送數據時對此進行標記。在連接建立時,雙方會協商一個初始序號。比如,一個 TCP 報文段攜帶了 1000 個字節的數據,序號為 500,那么這 1000 個字節在字節流中的位置就是從 500 到 1499 。
- 確認序號(32 位):僅當 ACK 標志位為 1 時有效。它表示接收方期望收到發送方下一個報文段的第一個數據字節的序號,用來告訴發送方哪些數據已經成功接收,哪些需要重發。例如,接收方收到了序號為 1 - 1000 的字節,期望接收下一個報文段從 1001 開始,那么確認序號就設置為 1001 。
序號、確認序號:
好比快遞的 “編號 + 簽收反饋”。
- 序號:包裹編號(比如 “第 500 號包裹”),方便快遞站(接收方)按順序整理;
- 確認序號:簽收單(比如 “已收到 1 - 500 號包裹,下一個要 501 號”),告訴發貨方 “哪些包裹收到了,接下來該發啥”。
- 首部長度(4 位):也叫數據偏移,它指出 TCP 報文段的數據起始處距離 TCP 報文段的起始處有多遠,即首部的長度。由于首部中可能包含可變長度的選項部分,因此需要這個字段來明確首部的長度。該字段以 4 字節為單位,所以 TCP 首部最長為 60 字節(2^4 - 1 = 15,15 * 4 = 60 )。
首部長度:
類似 “面單有多大”。面單可能貼了 “加急貼紙”“保價標簽”(對應 TCP 選項),所以得標出面單總長度,好讓快遞站知道 “從哪開始是包裹里的東西”。
- 保留(6 位):保留為今后使用,目前應置為 0。
- 標志位(6 位)
- URG(Urgent,緊急標志):當 URG = 1 時,表明緊急指針字段有效,告訴系統此報文段中有緊急數據,應盡快傳送(相當于高優先級處理)。
- URG(緊急):“加急件!優先送!”(比如游戲里的 “緊急技能指令”,要立刻處理);
- ACK(Acknowledgment,確認標志):當 ACK = 1 時,確認序號字段才有效。TCP 規定,在連接建立后所有傳送的報文段都必須把 ACK 置為 1。
- ACK(確認):“已收到!”(簽收反饋,告訴發貨方 “包裹到了”);
- PSH(Push,推送標志):當兩個應用進程進行交互式的通信時,有時在一端的應用進程希望在鍵入一個命令后立即就能收到對方的響應。在這種情況下,TCP 就可以使用推送操作,發送方的 TCP 把 PSH 置為 1,并立即創建一個報文段發送出去;接收方的 TCP 收到 PSH = 1 的報文段,就盡快地(即 “推送” 向前)交付接收應用進程,而不再等到整個緩存都填滿了后再向上交付。
- PSH(推送):“別存著,馬上送!”(比如你點外賣,商家做好就立刻送,不等湊滿單);
- RST(Reset,復位標志):當 RST = 1 時,表明 TCP 連接中出現嚴重錯誤(如主機崩潰或其他原因),必須釋放連接,然后再重新建立運輸連接。
- RST(復位):“包裹壞了,重發!”(比如運輸中包裹破損,要求重新發貨);
- SYN(Synchronize,同步標志):在連接建立時用來同步序號。當 SYN = 1,ACK = 0 時,表示這是一個連接請求報文段;若對方同意建立連接,則響應報文中 SYN = 1,ACK = 1 ,用于三次握手中。
- SYN(同步):“準備發貨!”(和商家建立 “發貨 - 收貨” 的約定,對應 TCP 三次握手的 “發起連接”);
- FIN(Finish,結束標志):用來釋放一個連接。當 FIN = 1 時,表明此報文段的發送方的數據已經發送完畢,并要求釋放運輸連接。
- FIN(結束):“沒貨了,不發了!”(告訴商家 “不再發貨了,結束合作”,對應斷開連接)。
- 窗口(16 位):用來讓發送方設置其發送窗口的大小,單位是字節。該字段反映了接收方當前接收緩存的空閑空間大小,從而控制發送方發送數據的速率,實現流量控制。例如,接收方的接收緩存還剩 10000 字節的空間,那么它可能會在確認報文中將窗口值設置為 10000,告知發送方最多可以發送 10000 字節的數據 。
- 窗口:
好比 “收貨方的倉庫剩余空間”。比如你家倉庫只能再放 10 個包裹,就告訴快遞站 “最多再發 10 個”,防止倉庫爆倉(流量控制)。
- 校驗和(16 位):校驗的范圍包括首部和數據這兩部分。在計算校驗和時,要在 TCP 報文段的前面加上 12 字節的偽首部。偽首部包含 IP 首部一些字段,其目的是讓 TCP 兩次檢查數據是否已經正確到達目的地(例如,檢查 IP 數據報是否已經到達正確的主機和端口)。
- 校驗和:
像 “包裹防偽碼”。快遞站會檢查防偽碼,確保包裹在運輸中沒被篡改、損壞(比如零食沒變質)。
- 緊急指針(16 位):僅在 URG = 1 時有效。它指出在本報文段中緊急數據共有多少個字節(緊急數據放在本報文段數據的最前面 )。
僅當 URG = 1 時有用,類似 “加急件里,前 5 件是最急的”,告訴快遞站 “緊急內容的范圍”。
- 選項(長度可變):最常見的可選字段是最長報文段 MSS(Maximum Segment Size)。MSS 告訴對方 TCP:“我的緩存所能接收的報文段的數據字段的最大長度是 MSS 個字節” 。
額外的 “特殊要求”,比如 “保價 100 元”“周六再送”(對應 TCP 里的 “最大報文段長度 MSS” 等特殊設置)。
數據部分
存放應用層交付給 TCP 的數據,其長度是可變的,并且在一些情況下(如建立連接的 SYN 報文段),數據部分可能為空。
TCP 報文段的格式設計緊密圍繞著其可靠傳輸、流量控制、擁塞控制以及連接管理等核心功能,每一個字段都在保障網絡數據準確、高效傳輸的過程中發揮著不可或缺的作用。
三次握手(建立連接)
TCP 的三次握手是建立連接時客戶端和服務器之間的 “三次對話”,目的是確認雙方都能正常收發數據,就像打電話時互相確認 “能聽到嗎” 一樣。咱們用 “打電話” 的場景通俗講解:
三次握手的完整過程
假設 客戶端 是你,服務器 是朋友:
1. 第一次握手:你先 “撥號”
- 客戶端→服務器:發送一個 “SYN” 標志的報文(類似你打電話時說:“喂,是小明嗎?能聽到我說話嗎?”)。
- 報文里會帶上客戶端的 “初始序號”(比如 x),表示 “我接下來要發的數據就從這個序號開始算”。
- 此時客戶端狀態:“我已發出請求,等待對方回應”(SYN-SENT)。
2. 第二次握手:朋友 “回應”
- 服務器→客戶端:收到請求后,回復一個 “SYN+ACK” 標志的報文(類似朋友說:“我能聽到你!你能聽到我嗎?”)。
- 報文里包含兩個關鍵信息:
- 服務器的 “初始序號”(比如 y),表示 “我接下來發的數據從這個序號開始”;
- 確認序號(x+1),表示 “我已收到你序號 x 的請求,下次請從 x+1 開始發”。
- 此時服務器狀態:“我已回應請求,等待對方確認”(SYN-RCVD)。
3. 第三次握手:你 “確認”
- 客戶端→服務器:收到回應后,再發一個 “ACK” 標志的報文(類似你說:“我也能聽到你!那我們開始聊吧~”)。
- 報文里的確認序號是(y+1),表示 “我已收到你序號 y 的回應,下次請從 y+1 開始發”。
- 此時客戶端狀態:“連接已建立”(ESTABLISHED);服務器收到后也進入 “連接已建立” 狀態,雙方可以開始傳輸數據了。
1.為什么需要三次握手?
核心是為了 防止 “已失效的連接請求” 干擾正常通信。
舉個例子:
如果客戶端很久以前發的一個連接請求(因網絡延遲)突然傳到服務器,服務器以為是新請求,就會回應并建立連接,但客戶端其實已經不需要了,這會浪費服務器資源。
三次握手通過 “客戶端最后一次確認”,確保雙方都認可 “這是一個有效的新連接”,避免上述問題。
2.TCP 三次握手建立連接的過程中,客戶端和服務器會經歷不同的狀態變化?
三次握手的狀態變遷(客戶端 vs 服務器)
初始狀態
- 客戶端:處于 CLOSED(關閉) 狀態(未發起任何連接請求)。
- 服務器:處于 LISTEN(監聽) 狀態(已準備好接收連接請求,比如 Web 服務器啟動后等待瀏覽器連接)。
第一次握手:客戶端發起連接請求
- 客戶端動作:向服務器發送 SYN 報文(包含客戶端初始序號),請求建立連接。
- 客戶端狀態:從
CLOSED
→ SYN-SENT(同步已發送)(表示 “已發請求,等待服務器回應”)。 - 服務器狀態:仍為
LISTEN
(尚未收到請求)。
第二次握手:服務器回應請求
- 服務器動作:收到客戶端的 SYN 報文后,回復 SYN+ACK 報文(包含服務器初始序號和對客戶端的確認序號)。
- 服務器狀態:從
LISTEN
→ SYN-RCVD(同步已接收)(表示 “已收到請求并回應,等待客戶端確認”)。 - 客戶端狀態:仍為
SYN-SENT
(尚未收到服務器回應)。
第三次握手:客戶端確認連接
- 客戶端動作:收到服務器的 SYN+ACK 報文后,發送 ACK 報文(包含對服務器的確認序號)。
- 客戶端狀態:從
SYN-SENT
→ ESTABLISHED(已建立連接)(表示 “雙方已確認,連接就緒”)。 - 服務器動作:收到客戶端的 ACK 報文后,確認連接建立。
- 服務器狀態:從
SYN-RCVD
→ ESTABLISHED(已建立連接)。
狀態總結表
階段 | 客戶端狀態 | 服務器狀態 | 核心動作 |
初始階段 | CLOSED(關閉) | LISTEN(監聽) | 服務器等待連接,客戶端未發起請求 |
第一次握手后 | SYN-SENT(同步已發送) | LISTEN(監聽) | 客戶端發 SYN,等待服務器回應 |
第二次握手后 | SYN-SENT(同步已發送) | SYN-RCVD(同步已接收) | 服務器發 SYN+ACK,等待客戶端確認 |
第三次握手后 | ESTABLISHED(已建立) | ESTABLISHED(已建立) | 客戶端發 ACK,雙方連接就緒,可傳數據 |
通俗類比:用 “約飯” 理解狀態
- CLOSED(客戶端):你還沒打算約朋友吃飯(未行動)。
- LISTEN(服務器):朋友說 “我今天有空,隨時可以約”(等待被約)。
- SYN-SENT(客戶端):你發消息問朋友 “今晚一起吃飯嗎?”(已發起請求,等回復)。
- SYN-RCVD(服務器):朋友回消息 “好啊!你想吃火鍋還是燒烤?”(已回應,等你確認)。
- ESTABLISHED(雙方):你回 “吃火鍋吧!”(確認達成一致,約飯成功,可進一步討論時間地點)。
關鍵說明
- 狀態變遷的核心是 “確認雙方收發能力”:每次狀態變化都對應一次報文交互,直到雙方都進入
ESTABLISHED
狀態,才意味著連接正式建立,可開始傳輸數據。 - 如果握手過程中出現超時(如客戶端發 SYN 后沒收到回應),客戶端會重發 SYN 報文,多次失敗后會放棄連接,回到
CLOSED
狀態。
理解這些狀態,有助于排查連接建立失敗的問題(比如服務器長期停留在 SYN-RCVD
狀態,可能是客戶端未發送第三次握手的 ACK 報文)。
四次揮手 (斷開連接)
TCP的四次揮手是斷開連接時客戶端和服務器之間的“四次對話”,整個過程中雙方會經歷不同的狀態變化,就像“結束通話前的禮貌告別流程”。以下是具體狀態及對應過程:
四次揮手的狀態變遷(客戶端 vs 服務器)
初始狀態
- 客戶端和服務器:均處于 ESTABLISHED(已建立連接) 狀態(正在傳輸數據或待命)。
第一次揮手:客戶端發起斷開請求
- 客戶端動作:當客戶端數據發送完畢,向服務器發送 FIN報文(表示“我這邊數據發完了,準備斷開”)。
- 客戶端狀態:從
ESTABLISHED
→ FIN-WAIT-1(終止等待1)(表示“已發斷開請求,等待服務器確認”)。 - 服務器狀態:仍為
ESTABLISHED
(尚未收到斷開請求)。
第二次揮手:服務確認收到請求
- 服務器動作:收到客戶端的FIN報文后,立即回復 ACK報文(表示“我收到你的斷開請求了,但我這邊可能還有數據沒發完,請等一下”)。
- 服務器狀態:從
ESTABLISHED
→ CLOSE-WAIT(關閉等待)(表示“已確認客戶端要斷開,正在處理剩余數據”)。 - 客戶端狀態:從
FIN-WAIT-1
→ FIN-WAIT-2(終止等待2)(表示“收到服務器確認,等待服務器發它的斷開請求”)。
第三次揮手:服務器發送斷開請求
- 服務器動作:當服務器剩余數據發送完畢,向客戶端發送 FIN報文(表示“我這邊數據也發完了,可以斷開了”)。
- 服務器狀態:從
CLOSE-WAIT
→ LAST-ACK(最后確認)(表示“已發斷開請求,等待客戶端最后確認”)。 - 客戶端狀態:仍為
FIN-WAIT-2
(尚未收到服務器的FIN報文)。
第四次揮手:客戶端確認斷開
- 客戶端動作:收到服務器的FIN報文后,發送 ACK報文(表示“收到你的斷開請求,確認斷開”),并等待一段時間(2MSL,確保服務器收到確認)。
- 客戶端狀態:從
FIN-WAIT-2
→ TIME-WAIT(時間等待) → 最終變為CLOSED(關閉)
(等待超時后徹底關閉)。 - 服務器動作:收到客戶端的ACK報文后,確認斷開。
- 服務器狀態:從
LAST-ACK
→ CLOSED(關閉)。
狀態總結表
階段 | 客戶端狀態 | 服務器狀態 | 核心動作 |
初始階段 | ESTABLISHED(已建立) | ESTABLISHED(已建立) | 雙方正常連接,可傳輸數據 |
第一次揮手后 | FIN-WAIT-1(終止等待1) | ESTABLISHED(已建立) | 客戶端發FIN,等服務器確認 |
第二次揮手后 | FIN-WAIT-2(終止等待2) | CLOSE-WAIT(關閉等待) | 服務器發ACK,處理剩余數據 |
第三次揮手后 | FIN-WAIT-2(終止等待2) | LAST-ACK(最后確認) | 服務器發FIN,等客戶端確認 |
第四次揮手后 | TIME-WAIT(時間等待)→ CLOSED | CLOSED(關閉) | 客戶端發ACK,等待超時后徹底關閉 |
通俗類比:用“結束通話”理解狀態
- ESTABLISHED:你和朋友正在通話(正常聊天)。
- FIN-WAIT-1:你說“我沒什么要說的了,掛了啊?”(發FIN,等朋友回應)。
- CLOSE-WAIT:朋友說“知道了,我還有最后一句話”(發ACK,處理剩余內容)。
- FIN-WAIT-2:你聽著朋友說最后一句話(等朋友說完)。
- LAST-ACK:朋友說“我說完了,掛吧”(發FIN,等你確認)。
- TIME-WAIT:你說“好的,再見”(發ACK),并等幾秒再掛(確保朋友聽到)。
- CLOSED:雙方都掛了電話(連接徹底關閉)。
關鍵說明
- TIME-WAIT的作用:客戶端等待2MSL(報文最大生存時間),是為了確保服務器能收到最后的ACK(如果服務器沒收到,會重發FIN,客戶端可再次確認),避免服務器因沒收到確認而一直處于
LAST-ACK
狀態。 - CLOSE-WAIT的意義:服務器在
CLOSE-WAIT
狀態停留的時間,取決于它處理剩余數據的耗時(如果長期停留,可能是服務器程序有bug,沒及時處理完數據)。
理解這些狀態,有助于排查連接斷開的問題(比如客戶端長期處于TIME-WAIT
可能導致端口耗盡,服務器長期CLOSE-WAIT
可能是代碼未釋放連接)。
重傳機制:
在TCP協議的可靠傳輸機制中,超時重傳、快速重傳和SACK(選擇性確認)是三種關鍵技術,它們各有側重又相互配合。下面分別用專業和通俗的方式講解:
一、超時重傳(Timeout Retransmission)
專業解釋:
超時重傳是最基礎的重傳機制。發送方在發送數據后會啟動一個計時器(超時時間RTO),如果在計時器到期前沒有收到接收方的確認(ACK),就認為數據丟失,會重新發送該數據。
超時時間(RTO)不是固定值,會根據網絡狀況動態調整(比如網絡延遲高時,RTO會自動增大)。
通俗理解:
就像你給朋友發微信消息,設置了"5分鐘沒回復就再發一次"。如果5分鐘內沒收到朋友的回復(可能消息丟了,也可能朋友沒看到),你就再發一次同樣的消息。
特點:
- 優點:實現簡單,是所有可靠傳輸的基礎保障
- 缺點:等待超時時間可能較長,影響傳輸效率(比如網絡只是短暫波動,卻要等完整的超時時間)
二、快速重傳(Fast Retransmit)
專業解釋:
當發送方連續收到3個相同的重復確認(Duplicate ACK)時,無需等待超時計時器到期,就立即重傳未被確認的數據。
重復確認指的是:接收方收到了亂序的數據,會重復發送已正確接收的最后一個數據的ACK。例如,發送方發送1、2、3、4、5,接收方收到1、3,會連續發送3次"已收到1"的ACK,此時發送方就知道2丟失了,會立即重傳2。
通俗理解:
你給朋友發了5條連續的消息:消息1、消息2、消息3、消息4、消息5。
朋友收到了消息1和消息3,但沒收到消息2,于是連續回復你3次"我收到消息1了"。
你一看,收到3次同樣的回復,就知道朋友肯定沒收到消息2,不等5分鐘超時,馬上重發消息2。
特點:
- 優點:比超時重傳更及時,減少了等待時間,提高了傳輸效率
- 缺點:只能判斷出"有數據丟失",但不知道具體丟失了哪些數據(當丟失多個連續數據時效率不高)
三、SACK(Selective Acknowledgment,選擇性確認)
專業解釋:
SACK是對快速重傳的增強,允許接收方在ACK中明確告知發送方"哪些數據已經收到",而不僅僅是"最后一個正確收到的數據"。
通過SACK,接收方可列出已正確接收的所有數據段范圍,發送方就能精確知道哪些數據丟失了,只重傳丟失的部分,而不用重傳后續所有數據。
通俗理解:
你給朋友發了10條消息(1-10),朋友收到了1-3、6-10,但沒收到4-5。
沒有SACK時,朋友只能說"我收到3了";
有SACK時,朋友會明確告訴你"我收到了1-3和6-10"。
你一看就知道只有4-5丟了,只重發這兩條即可,不用重發6-10。
特點:
- 優點:能精確識別丟失的數據,減少不必要的重傳,極大提高傳輸效率,特別適合網絡狀況較差、經常有數據丟失的場景
- 缺點:需要雙方支持該選項,增加了協議的復雜度
三者關系總結:
- 超時重傳是"保底機制",無論其他機制是否生效,超時后一定會重傳
- 快速重傳是"效率優化",通過重復ACK提前發現丟失,不用等超時
- SACK是"精確制導",讓重傳更精準,避免無效重傳
實際網絡中,這三種機制通常一起工作:先嘗試SACK+快速重傳實現高效修復,若失敗則等待超時重傳作為最后保障,共同保證數據可靠且高效地傳輸。
滑動窗口
9.1. 概述
滑動窗口是 TCP 協議中用于實現流量控制和高效數據傳輸的一種機制。它允許發送方在等待接收方確認的同時,連續發送多個數據段,從而提高網絡利用率,同時避免發送過多數據導致接收方緩沖區溢出。
9.2. 什么是窗口?
- 專業詳解:窗口本質上是一個大小可變的緩沖區,對于發送方來說,發送窗口表示在未收到確認的情況下,最多可以發送的數據量;對于接收方來說,接收窗口表示自己當前能夠接收的數據量。窗口的大小由接收方根據自身的緩沖區情況來決定,并通過 ACK 報文告知發送方。
- 通俗理解:想象發送方是一個快遞發貨站,接收方是一個快遞代收點。窗口就像是代收點能容納包裹的空間,發貨站在代收點確認收到包裹之前,最多能發出去的包裹數量就是發送窗口大小,代收點能接收的包裹數量就是接收窗口大小。
9.3. 窗口大小由誰決定?
窗口大小主要由接收方決定。接收方會根據自己的接收緩沖區剩余空間來設置接收窗口大小,并通過 ACK 報文將這個信息告知發送方。發送方的發送窗口大小不能超過接收方告知的接收窗口大小。
- 通俗理解:還是以快遞為例,代收點能收多少包裹,就告訴發貨站 “我最多還能收這么多”,發貨站就按照代收點說的數量來發貨。
9.4. 發送方的滑動窗口
- 專業詳解:發送方的滑動窗口包含了已經發送但未被確認的數據段,以及可以繼續發送的數據段。隨著接收方不斷返回確認信息,窗口會不斷向右滑動,新的數據段可以被發送。
- 通俗理解:發貨站有一個待發貨的包裹隊列,滑動窗口就像是一個框,框內的包裹是可以直接發貨的。當收到代收點對框內部分包裹的確認后,框就會向右移動,后面的包裹就進入了可發貨范圍。
9.5. 實現機制
通過 TCP 報文中的序號(Seq)和確認號(Ack),以及窗口字段來實現。發送方根據接收方告知的窗口大小,控制發送數據的量;接收方在收到數據后,返回包含確認號和窗口大小的 ACK 報文,告知發送方哪些數據已接收,以及還能接收多少數據。
9.6. 作用
- 流量控制:防止發送方發送數據過快,導致接收方緩沖區溢出。
- 提高效率:允許發送方連續發送多個數據段,減少了等待確認的時間,提高了網絡利用率。
9.7. 窗口滑動過程
可以參考之前你提供的那張窗口滑動過程圖,發送方發送數據,接收方確認數據,隨著確認的進行,發送方的窗口不斷向右滑動,允許發送更多的數據。
10. 流量控制
- 專業詳解:流量控制是一種端到端的控制機制,主要是為了防止發送方發送數據的速率過快,導致接收方來不及處理,造成數據丟失。它通過接收方告知發送方自己的接收窗口大小,來限制發送方的發送速率。
- 通俗理解:還是用快遞的例子,發貨站發貨太快,代收點來不及接收和存放包裹,就會告訴發貨站 “你慢點發,我現在只能收這么多”,以此來控制發貨的流量。
11. 擁塞控制
11.1. 擁塞控制與流量控制的區別
- 專業詳解:流量控制是端到端的,關注的是發送方和接收方之間的關系,防止接收方緩沖區溢出;而擁塞控制是全局性的,關注的是網絡整體的狀況,防止網絡出現擁塞(如鏈路擁塞、路由器過載等)。擁塞控制通過調整發送方的發送速率,來適應網絡的承載能力。
- 通俗理解:流量控制就像是發貨站和代收點之間的協調,避免代收點爆倉;擁塞控制則像是整個快遞運輸網絡的管理,避免交通擁堵,比如當很多發貨站都在大量發貨,導致運輸路線擁堵時,就需要控制發貨站的發貨速度。
這是 TCP 擁塞控制四大算法(慢啟動、擁塞避免、擁塞發生、快速恢復)的完整流程拆解,結合圖和實際場景講透邏輯:
一、核心目標:TCP 如何 “聰明地發數據”?
網絡就像高速公路,數據是汽車:
- 發太快 → 堵車(網絡擁塞),數據丟包、延遲高;
- 發太慢 → 浪費帶寬,傳輸效率低
TCP 用 擁塞窗口(cwnd) 當 “油門”:cwnd 越大,發得越快;cwnd 越小,發得越慢。
四大算法的作用:動態調整 cwnd,讓網絡 “不堵車又高效”。
二、1. 慢啟動(Slow Start):“輕輕踩油門,試探路況”
核心邏輯:
- 初始
cwnd = 1
(只能發 1 個數據包); - 每收到 1 個確認(ACK),
cwnd 翻倍
(指數增長:1→2→4→8…); - 直到
cwnd 觸達慢啟動門限(ssthresh)
,切換到擁塞避免。
圖中流程(以輪次理解):
- 輪次 1:
cwnd=1
,發 1 個包(M?),收到 ACK 后,cwnd=2
; - 輪次 2:
cwnd=2
,發 2 個包(M?~M?),收到 ACK 后,cwnd=4
; - 輪次 3:
cwnd=4
,發 4 個包(M?~M?),收到 ACK 后,cwnd=8
; - …… 直到
cwnd
觸達ssthresh
(圖中是 8),進入擁塞避免。
通俗類比:
你上高速前,不知道路況,先以 10km/h(cwnd=1
)試探,發現路空,加到 20km/h(cwnd=2
),再發現路還空,加到 40km/h(cwnd=4
)…… 直到接近 “限速”(ssthresh
),才穩定加速。
三、2. 擁塞避免(Congestion Avoidance):“穩定加速,別搞堵車”
核心邏輯:
- 當
cwnd ≥ ssthresh
時,進入擁塞避免; - 每收到一輪 ACK(所有發送的包都確認),
cwnd 只加 1
(線性增長:8→9→10…)。
圖中流程:
ssthresh=8
,cwnd
到 8 后,每輪次只 +1:
輪次 4:cwnd=8
→ 發 8 個包 → 收 ACK →cwnd=9
;
輪次 5:cwnd=9
→ 發 9 個包 → 收 ACK →cwnd=10
;
…… 緩慢增長,避免網絡擁塞。
通俗類比:
接近高速限速(ssthresh
)后,保持 “穩定加速”,比如從 80km/h 慢慢加到 81、82…,別突然飆到 120 搞堵車。
四、3. 擁塞發生(Congestion Occurs):“堵車了!快剎車”
觸發條件:
網絡丟包時,TCP 認為 “堵車了”,觸發擁塞發生。丟包的判斷有兩種:
- 超時重傳:發完包后,超時沒收到 ACK(路徹底堵死,包沒回來);
- 快速重傳:收到 3 個重復 ACK(路沒全堵,但有包丟了,后面的包先到了)。
處理邏輯(分場景):
場景 1:超時重傳(圖中左半部分)
ssthresh = cwnd/2
(比如cwnd=12
→ssthresh=6
);cwnd=1
(急剎車,重新慢啟動);- 重新從
cwnd=1
開始指數增長,直到觸達新的ssthresh
。
場景 2:快速重傳(圖中未單獨畫,但為快速恢復鋪墊)
- 收到 3 個重復 ACK,認為 “丟了一小部分包”,觸發快速恢復(下文講)。
通俗類比:
- 超時重傳:高速徹底堵死(包超時沒回來),你只能剎車到 10km/h(
cwnd=1
),重新試探; - 快速重傳:高速上有車禍(丟了幾個包),但還能緩慢移動,不用徹底剎車。
五、4. 快速恢復(Fast Recovery):“小堵車,緩緩開”
核心邏輯(基于快速重傳觸發):
ssthresh = cwnd/2
(比如cwnd=12
→ssthresh=6
);cwnd = ssthresh + 3
(因為收到 3 個重復 ACK,說明有 3 個包已經 “在路上”,可以稍微加速);- 之后每收到 1 個 ACK,
cwnd +1
(線性增長,恢復傳輸)。
圖中流程:
- 觸發快速重傳后,
cwnd
從ssthresh+3
開始,緩慢增長回到擁塞避免階段。
通俗類比:
高速上遇到小事故(丟包),但車流還能動,你把速度降到 63km/h(ssthresh+3
),然后慢慢加到 70、80…,恢復正常。
六、四大算法的協同關系
- 慢啟動:從 0 開始,快速試探網絡(指數增長);
- 擁塞避免:觸達門限后,穩定增長(線性增長);
- 擁塞發生:丟包時,急剎車(超時重傳)或緩剎車(快速重傳);
- 快速恢復:緩剎車后,慢慢恢復速度。
本質是 TCP 的 “自適應策略”:先試探、再穩定、遇堵剎車、小堵緩恢復,讓網絡在 “高效” 和 “不擁塞” 之間找平衡。
總結
記住一個比喻:
TCP 像 “聰明的司機”,用 慢啟動試探高速(網絡)路況,擁塞避免穩定加速,遇到堵車(丟包)時,嚴重堵車就徹底剎車重啟(超時重傳),小堵車就緩剎車慢慢恢復(快速重傳 + 快速恢復),最終讓數據傳輸又快又穩。
12. TCP 協議如何保證可靠性傳輸?
- 專業詳解:通過序列號和確認號機制,確保數據按序到達;通過重傳機制(超時重傳、快重傳),保證丟失的數據能夠被重新發送;通過校驗和,檢測數據在傳輸過程中是否發生錯誤;通過流量控制和擁塞控制,避免網絡擁塞和接收方緩沖區溢出,保證數據穩定傳輸。
- 通俗理解:就像寄重要文件,給每個文件編號(序列號),對方收到后確認(確認號);如果沒收到或者文件有問題,就重新寄(重傳);寄之前檢查文件是否完整(校驗和);還要根據對方接收能力和運輸路況(流量控制和擁塞控制)來調整寄件速度。
13. TCP 粘包
13.1. 產生原因
- 專業詳解:TCP 是面向字節流的協議,發送方將數據寫入套接字緩沖區,接收方從套接字緩沖區讀取數據。當發送方連續發送多個小數據段時,這些數據可能會被合并成一個大的數據段發送;而接收方讀取數據時,也可能一次性讀取了多個發送方的數據,導致數據邊界不清晰,產生粘包現象。
- 通俗理解:你要發送多條短消息,這些消息在傳輸過程中可能被 “粘” 在一起發送,接收方收到后分不清哪條消息是哪條。
13.2. 解決辦法
- 消息定長:發送方和接收方約定好每個消息的固定長度,接收方每次按固定長度讀取數據。
- 添加消息邊界:在每個消息末尾添加特殊的邊界標識,接收方根據邊界標識來區分不同的消息。
- 在消息頭中記錄消息長度:發送方在消息頭中寫入消息的實際長度,接收方先讀取消息頭獲取消息長度,再按長度讀取完整的消息。