一、TCP的定位與核心特性
TCP(Transmission Control Protocol,傳輸控制協議)是TCP/IP協議棧中傳輸層的核心協議,與UDP(用戶數據報協議)共同承擔端到端數據傳輸功能。其設計目標是在不可靠的IP網絡上提供可靠、有序、面向連接的字節流服務,是互聯網中絕大多數應用(如HTTP、FTP、SMTP等)的基礎。
與UDP相比,TCP的核心特性差異如下:
- 面向連接:通信前需通過“三次握手”建立連接,結束后需“四次揮手”釋放連接;UDP無連接。
- 可靠傳輸:通過序號、確認、重傳等機制確保數據不丟失、不重復、按序到達;UDP不保證可靠性。
- 字節流服務:將應用層數據視為連續字節流,無消息邊界;UDP保留消息邊界。
- 流量控制與擁塞控制:通過滑動窗口避免接收方緩沖區溢出,通過擁塞算法避免網絡擁塞;UDP無此類機制。
- 適用于場景:對可靠性要求高(如文件傳輸、網頁加載);UDP適用于實時性要求高(如視頻通話、游戲)。
二、TCP報文結構
TCP報文由首部和數據兩部分組成,首部最小20字節,最大60字節(含選項字段)。各字段含義如下:
字段 | 長度(字節) | 含義 |
---|---|---|
源端口/目的端口 | 2/2 | 標識發送端和接收端的應用進程(如HTTP默認80端口)。 |
序號(Sequence Number) | 4 | 本報文數據段第一個字節的序號(用于按序重組和去重)。 |
確認號(Acknowledgment Number) | 4 | 期望接收的下一字節序號(僅當ACK=1時有效,即確認已收到序號≤(確認號-1)的數據)。 |
數據偏移(Header Length) | 4位 | 表示TCP首部長度(以32位字為單位,最小值5(20字節),最大值15(60字節))。 |
保留位 | 6位 | 預留未來使用,目前需設為0。 |
控制位(Flags) | 6位 | 共6個標志位:URG(緊急指針有效)、ACK(確認號有效)、PSH(推數據至應用層)、RST(重置連接)、SYN(同步序號,建立連接)、FIN(終止連接)。 |
窗口大小(Window) | 2字節 | 接收窗口(rwnd),告知發送方可接收的字節數(流量控制核心字段)。 |
校驗和(Checksum) | 2字節 | 用于檢測報文段在傳輸中是否損壞(覆蓋偽首部、TCP首部、數據)。 |
緊急指針(Urgent Pointer) | 2字節 | 當URG=1時有效,指示緊急數據在報文段中的偏移量(緊急數據優先處理)。 |
選項(Options) | 0-40字節 | 可選字段,如MSS(最大報文段長度)、SACK(選擇確認)、Window Scale(窗口擴大因子)等。 |
三、TCP連接管理
TCP是“面向連接”的協議,連接管理包含建立連接(三次握手) 和釋放連接(四次揮手) 兩個過程,通過控制位(SYN、ACK、FIN)實現。
1. 三次握手(建立連接)
三次握手的目標是:① 確保雙方收發能力正常;② 協商初始序號(ISN);③ 同步連接狀態。流程如下:
-
第一次握手:客戶端 → 服務器
發送SYN報文(SYN=1,ACK=0),攜帶客戶端初始序號ISN_c(如x)。此時客戶端進入SYN_SENT
狀態。 -
第二次握手:服務器 → 客戶端
服務器收到SYN后,回復SYN+ACK報文(SYN=1,ACK=1),攜帶服務器初始序號ISN_s(如y),并確認客戶端序號(確認號=ISN_c+1=x+1)。此時服務器進入SYN_RCVD
狀態。 -
第三次握手:客戶端 → 服務器
客戶端收到SYN+ACK后,發送ACK報文(ACK=1),確認服務器序號(確認號=ISN_s+1=y+1)。此時客戶端進入ESTABLISHED
狀態;服務器收到ACK后也進入ESTABLISHED
狀態,連接建立。
為何需要三次握手?
- 防止“過期連接請求”干擾:若客戶端的SYN報文因網絡延遲到達服務器,服務器會誤以為是新連接并回復SYN+ACK。若僅兩次握手,服務器會直接建立連接并等待數據,但客戶端已丟棄該過期請求,導致服務器資源浪費。三次握手通過客戶端的最終ACK,確保雙方確認“當前連接有效”。
用最簡單的例子解釋為什么需要三次握手:
A: 喂,能聽見嗎?
B: 能聽見,你能聽見我嗎?
A: 能聽見。
2. 四次揮手(釋放連接)
TCP支持“半關閉”(一方關閉發送后仍可接收數據),因此釋放連接需四次交互:
-
第一次揮手:客戶端 → 服務器
客戶端主動關閉,發送FIN報文(FIN=1,ACK=1),表示不再發送數據(但可接收),攜帶序號u(最后發送字節的序號+1)。客戶端進入FIN_WAIT_1
狀態。 -
第二次揮手:服務器 → 客戶端
服務器收到FIN后,回復ACK報文(ACK=1),確認號=u+1,告知客戶端“已收到關閉請求”。服務器進入CLOSE_WAIT
狀態,客戶端進入FIN_WAIT_2
狀態(等待服務器剩余數據)。 -
第三次揮手:服務器 → 客戶端
服務器發送完剩余數據后,發送FIN報文(FIN=1,ACK=1),攜帶序號v(服務器最后發送字節的序號+1),確認號=u+1(與第二次揮手一致)。服務器進入LAST_ACK
狀態。 -
第四次揮手:客戶端 → 服務器
客戶端收到FIN后,回復ACK報文(ACK=1),確認號=v+1,客戶端進入TIME_WAIT
狀態;服務器收到ACK后進入CLOSED
狀態。客戶端等待2MSL(最大報文段壽命,通常為1-2分鐘)后,也進入CLOSED
狀態,釋放連接。
四次揮手:
A:再見
B:收到
B:再見
A:收到
關鍵細節:
- 為何四次揮手? 第二次揮手(ACK)和第三次揮手(FIN)無法合并,因為服務器可能還有數據需發送(半關閉狀態)。
- TIME_WAIT狀態:持續2MSL(確保最后一個ACK被服務器收到;防止舊報文干擾新連接)。若服務器未收到ACK,會重發FIN,客戶端需在TIME_WAIT內處理。
3. TCP狀態機
連接管理的狀態轉換可通過狀態機描述,核心狀態包括:
- 客戶端:
CLOSED
→SYN_SENT
→ESTABLISHED
→FIN_WAIT_1
→FIN_WAIT_2
→TIME_WAIT
→CLOSED
- 服務器:
CLOSED
→LISTEN
→SYN_RCVD
→ESTABLISHED
→CLOSE_WAIT
→LAST_ACK
→CLOSED
異常狀態:RST
(重置連接,用于處理錯誤,如連接不存在時強制關閉)。
四、TCP可靠傳輸機制
TCP通過多重機制確保數據“可靠傳輸”(不丟失、不重復、按序到達),核心包括序號與確認、超時重傳、快速重傳與恢復、選擇確認(SACK) 等。
1. 序號與確認機制
- 序號:每個字節數據分配唯一序號(初始為ISN,后續按字節遞增)。例如,若ISN=100,發送50字節數據,序號為100-149,下一個序號為150。
- 確認號:采用“累計確認”,表示“已正確接收序號≤(確認號-1)的所有數據”,期望接收確認號對應的字節。例如,收到序號100-149的數據,確認號為150。
2. 超時重傳
當發送方未在規定時間內收到確認,會重傳該數據,關鍵是超時時間(RTO) 的計算:
- RTO需動態調整(基于RTT,往返時間):
- 樣本RTT(SampleRTT):單次報文往返時間;
- 平滑RTT(SRTT):SRTT = (1-α)×SRTT + α×SampleRTT(α通常為0.125);
- RTT偏差(RTTVAR):RTTVAR = (1-β)×RTTVAR + β×|SampleRTT - SRTT|(β通常為0.25);
- 最終RTO = SRTT + 4×RTTVAR(確保97%的RTT落在RTO內)。
3. 快速重傳與快速恢復
- 快速重傳:當發送方收到3個重復確認(確認號相同),無需等待超時,立即重傳未被確認的報文(推斷該報文已丟失)。
- 快速恢復:重傳后不執行慢啟動(避免網絡擁塞加劇),而是將擁塞窗口(cwnd)設為慢啟動閾值(ssthresh),直接進入擁塞避免階段。
4. 選擇確認(SACK)
累計確認的缺陷:若中間報文丟失,后續報文即使到達也無法被單獨確認。SACK通過選項字段告知發送方“已接收的非連續數據塊”,發送方僅重傳丟失部分。例如,接收方收到1-100、201-300,SACK會標記這兩個區間,發送方僅重傳101-200。
五、流量控制
流量控制用于防止發送方速率超過接收方處理能力,基于“滑動窗口機制”,通過接收窗口(rwnd)實現。
1. 滑動窗口原理
- 發送窗口:發送方可發送但未確認的數據范圍,大小由接收窗口(rwnd)和擁塞窗口(cwnd)共同決定(發送窗口=min(rwnd, cwnd))。
- 接收窗口:接收方緩沖區剩余空間(rwnd = 接收緩沖區大小 - 已接收未讀取數據量),通過TCP報文的“窗口大小”字段告知發送方。
窗口分為三部分:
- 已發送且確認:序號≤已確認序號;
- 已發送未確認:序號在已確認序號+1 至 發送窗口左沿-1;
- 未發送但可發送:序號在發送窗口左沿 至 發送窗口右沿-1;
- 不可發送:序號≥發送窗口右沿。
2. 窗口動態調整
- 接收方隨緩沖區使用情況更新rwnd(若緩沖區滿,rwnd=0);
- 發送方根據rwnd調整發送窗口:若rwnd=0,發送方停止發送,定期發送“零窗口探測報文”(1字節),接收方回復新的rwnd后恢復發送。
六、擁塞控制
擁塞控制用于防止發送方速率超過網絡承載能力(避免網絡擁塞導致丟包),核心是通過調整擁塞窗口(cwnd) 控制發送速率,涉及四大算法:慢啟動、擁塞避免、快重傳、快恢復。
1. 核心參數
- 擁塞窗口(cwnd):發送方根據網絡擁塞狀態動態調整的窗口(初始為1MSS);
- 慢啟動閾值(ssthresh):cwnd增長的臨界點(初始為較大值,如65535字節)。
2. 算法流程
- 慢啟動:cwnd從1MSS開始,每收到一個確認(或每經過一個RTT),cwnd翻倍(指數增長),直到cwnd達到ssthresh,進入擁塞避免階段。
- 擁塞避免:cwnd每經過一個RTT增加1MSS(線性增長),降低擁塞風險。
- 擁塞處理:
- 若超時重傳(嚴重擁塞):ssthresh = cwnd/2,cwnd重置為1MSS,重新慢啟動;
- 若收到3個重復確認(輕度擁塞):觸發快重傳,ssthresh = cwnd/2,cwnd = ssthresh,進入擁塞避免(快恢復)。
七、其他重要特性
- 面向字節流:TCP將應用數據視為連續字節流,無消息邊界,應用層需自行處理數據分割(如通過長度字段或分隔符)。
- 最大報文段長度(MSS):TCP報文段最大數據部分長度(MSS = MTU - IP首部長度 - TCP首部長度,以太網中通常為1460字節),在三次握手的SYN報文中協商。
- Nagle算法:減少小報文數量(如連續發送多個1字節數據),規則是:未確認數據時,僅當數據達MSS或收到確認,才發送。可通過
TCP_NODELAY
選項關閉(適用于實時性場景,如SSH)。 - 延遲確認:接收方不立即回復ACK,而是延遲500ms(或在發送數據時一并確認),減少ACK數量。若500ms內收到新數據,會合并確認。
八、常見問題與優化
-
粘包問題:TCP字節流無邊界,導致應用層收到的數據可能合并(粘包)或拆分。解決方法:
- 固定長度:每個消息固定大小;
- 分隔符:用特殊字符(如
\r\n
)分隔消息; - 長度前綴:消息頭部包含長度字段。
-
TIME_WAIT積累:高并發場景下,大量
TIME_WAIT
狀態連接會占用端口。優化方案:- 開啟
SO_REUSEADDR
:允許端口快速復用; - 縮短TIME_WAIT時長(如調整
net.ipv4.tcp_fin_timeout
)。
- 開啟
-
擁塞控制優化:傳統算法(如Reno)在高帶寬延遲網絡(如衛星鏈路)效率低,現代算法如BBR(基于帶寬和延遲)、CUBIC(基于三次函數增長)可提升性能。
TCP是互聯網可靠傳輸的基石,通過三次握手建立連接、四次揮手釋放連接,結合序號確認、超時重傳、SACK等機制確保可靠性,通過滑動窗口實現流量控制,通過慢啟動、擁塞避免等算法實現擁塞控制。理解TCP的核心機制,對網絡編程、性能優化及問題排查至關重要。其設計兼顧了可靠性與效率,是計算機網絡中最復雜且應用最廣泛的協議之一。