一、特點:
(一)面向連接
在進行數據傳輸之前,TCP 需要在發送方和接收方之間建立一條邏輯連接。這一過程類似于打電話,雙方在通話前需要先撥號建立連接。建立連接的過程通過三次握手來完成,確保通信雙方都做好了數據傳輸的準備。連接建立后,數據按照順序有序傳輸,直到通信結束,通過四次揮手關閉連接。
(二)可靠性
- 校驗和:TCP 在發送數據時,會對數據部分計算校驗和,并將校驗和放入 TCP 首部。接收方在接收到數據后,會重新計算校驗和并與接收到的校驗和進行對比。如果兩者不一致,說明數據在傳輸過程中出現了錯誤,接收方會要求發送方重新發送數據。
- 確認機制:接收方收到數據后,會向發送方發送確認(ACK)消息,告知發送方數據已成功接收。發送方在發送數據后,會啟動一個定時器,如果在定時器超時之前沒有收到 ACK,就會認為數據傳輸失敗,并重發數據。
- 重傳機制:除了超時重傳,TCP 還采用了快速重傳機制。當接收方連續收到三個相同的 ACK 時,就會認為中間的數據段丟失,發送方會立即重傳丟失的數據段,而不需要等待定時器超時,大大提高了數據傳輸的效率。
- 排序與重復數據處理:TCP 會對接收的數據按照序號進行排序,確保數據按順序交付給應用層。同時,對于重復接收的數據,TCP 會進行丟棄處理,保證應用層不會接收到重復的數據。
(三)字節流服務
TCP 將數據視為無結構的字節流進行傳輸,應用層可以按照任意大小的數據塊進行讀寫,而不必擔心數據的邊界問題。TCP 會在發送方將數據分割成合適大小的段進行傳輸,并在接收方將這些段重新組裝成完整的字節流交付給應用層。
二、連接管理機制
(一)連接建立(三次握手)
- 第一次握手:客戶端向服務器發送一個帶有 SYN(同步序列號)標志位的 TCP 報文段,該報文段中包含客戶端隨機生成的初始序列號(Sequence Number,簡稱 SEQ),假設為 x。此時客戶端進入 SYN_SENT 狀態,等待服務器的響應。
- 第二次握手:服務器接收到客戶端的 SYN 報文段后,向客戶端發送一個 SYN + ACK 報文段。該報文段中的 SYN 標志位表示服務器同意建立連接,ACK 標志位用于確認收到客戶端的 SYN。服務器也會生成一個自己的初始序列號,假設為 y,并將客戶端的序列號 x 加 1 作為確認號(Acknowledgment Number,簡稱 ACK),即 ACK = x + 1。此時服務器進入 SYN_RCVD 狀態。
- 第三次握手:客戶端接收到服務器的 SYN + ACK 報文段后,向服務器發送一個 ACK 報文段。該報文段的 ACK 標志位有效,確認號為服務器的序列號 y 加 1,即 ACK = y + 1,序列號為客戶端在第一次握手中發送的序列號 x 加 1,即 SEQ = x + 1。此時客戶端和服務器都進入 ESTABLISHED 狀態,連接建立成功。
(二)數據傳輸
連接建立后,客戶端和服務器就可以進行數據傳輸了。發送方將應用層的數據分割成 TCP 段,每個 TCP 段包含 TCP 首部和數據部分。TCP 首部中包含源端口、目的端口、序列號、確認號、標志位等信息。發送方按照序列號順序發送數據段,接收方接收數據段后,根據序列號進行排序,并向發送方發送 ACK 確認。如果發送方在規定時間內沒有收到 ACK,就會重發數據段。
(三)連接關閉(四次揮手)
- 第一次揮手:客戶端向服務器發送一個 FIN(結束標志位)標志位有效的 TCP 報文段,表示客戶端不再發送數據,但仍可以接收數據。此時客戶端進入 FIN_WAIT_1 狀態。
- 第二次揮手:服務器接收到客戶端的 FIN 報文段后,向客戶端發送一個 ACK 報文段,確認收到客戶端的 FIN,此時服務器進入 CLOSE_WAIT 狀態。客戶端收到 ACK 后,進入 FIN_WAIT_2 狀態。
- 第三次揮手:服務器在處理完剩余的數據后,向客戶端發送一個 FIN 標志位有效的 TCP 報文段,表示服務器也不再發送數據。此時服務器進入 LAST_ACK 狀態。
- 第四次揮手:客戶端接收到服務器的 FIN 報文段后,向服務器發送一個 ACK 報文段,確認收到服務器的 FIN。此時客戶端進入 TIME_WAIT 狀態,經過一段時間(通常為 2 倍的最大段生存期,即 2MSL)后,客戶端進入 CLOSED 狀態,徹底關閉連接。服務器在收到客戶端的 ACK 后,立即進入 CLOSED 狀態。
看到這,有的讀友可能會想到,建立連接時為什么需要3次握手?請求+響應兩次握手不行嗎?接下來就一同看看兩次握手會出現什么問題。
如上圖左邊場景,客戶端選擇一個初始序列號x,發送連接請求報文 req_conn(x)
給服務器,服務器接收到連接請求后,發送確認連接報文acc_conn(x)
,并且進入已連接狀態。而在客戶端超時定時器到時的時候,客戶端沒有接收到服務器的確認報文。此時,客戶端重發連接請求req_conn(x)
,一會兒,第一次的acc_conn到達客戶端處,連接建立,進行數據通信,然后通信結束。結束后,重發的req_conn(x)
到達了服務器,服務器端會認為又建立了一個新連接(因為它不記得之前已經處理過 ),又會發送acc_conn(x)
,而客戶端會忽略這個確認(因為已經建立連接 )。這就導致服務器端維護了多余的、不完整的連接(半連接 )。服務器端資源被無效占用,連接管理也出現混亂。
由此可看出,2次握手導致半連接問題
再看右側場景,建立連接過程中,由于某種原因,服務器端ack遲遲不到,致使客戶端超時重發req_conn(x)
,此后,延遲的ack
到達客戶端,連接建立。客戶端向服務器發送數據,而又由于某種原因,data
的ack
遲遲不到,客戶端超時重發數據data.重發后延遲的ack到達客戶端,通信結束,連接關閉。此后,重發的req_conn
及data
到達服務器,使得老的數據被當作新的數據接收。這將導致數據錯亂,業務邏輯錯誤
綜上,二次握手存在的問題如下:
問題類型 | 根本原因 | 后果 | 三次握手解決方案 |
半連接 | 缺乏客戶端最終確認 | 服務器資源浪費,通信中斷 | 通過第三次ACK驗證連接有效性 |
舊數據誤認 | 無法區分歷史連接與新連接 | 數據錯亂,業務邏輯錯誤 | 動態ISN + 序列號嚴格同步 |
雙向能力未驗證 | 僅驗證單向可達性 | 單向通信風險(如服務器→客戶端不可達) | 三次交互確認雙向鏈路 |
因此,必須采用三次握手。
三、可靠數據傳輸
1. 確認應答(ACK)機制
- 序列號與確認號:每個數據包攜帶32位序列號(SEQ)標識字節流起始位置,接收方通過確認號(ACK=SEQ+數據長度)反饋已接收的數據范圍。例如,發送方發送SEQ=1000、長度500的數據,接收方返回ACK=1500
- ACK標志位:TCP頭部中ACK標志位為1時,表示該報文為確認報文,此時確認號字段生效。普通數據報文ACK標志位為0 。
- 累積確認:接收方僅需確認連續接收的最高序列號,簡化ACK處理。例如,若接收方已收到SEQ=1000-2000的數據,即使中間有亂序包(如SEQ=2500),仍返回ACK=2001,觸發發送方選擇性重傳 。
2. 超時重傳與動態RTO
- 重傳觸發條件:發送方在動態計算的重傳超時時間(RTO)內未收到ACK,觸發數據包重傳。RTO基于往返時間(RTT)自適應調整,計算公式為:
SRTT = (1-α) * SRTT + α * RTT_sample
DevRTT = (1-β) * DevRTT + β * |RTT_sample - SRTT|
RTO = SRTT + 4 * DevRTT
其中,α=0.125,β=0.25(經驗值)。
- 超時加倍策略:首次超時后,RTO逐次加倍,避免網絡擁塞惡化 。
- 接收緩沖區去重:接收方通過緩沖區存儲已接收數據并按序重組,丟棄重復數據包(如因重傳導致的冗余包) 。
3. 滑動窗口與高效傳輸
- 窗口動態調整:發送窗口大小(SWND)取接收窗口(RWND)與擁塞窗口(CWND)的最小值,確保發送速率匹配接收方處理能力和網絡狀態。
- 批量發送與累積ACK:發送方可在窗口內連續發送多個數據包,接收方通過累積ACK減少確認次數。例如,發送窗口為4時,發送SEQ=1-4的數據包,接收方返回ACK=5確認全部接收。
- 選擇性確認(SACK):通過TCP選項字段標記非連續接收的數據塊范圍,發送方僅重傳丟失的包(如接收方反饋SACK=3000-3500,發送方重傳缺失的2500-3000) 。
- D-SACK:接收方通過SACK反饋重復接收的數據塊,幫助發送方區分ACK丟失或網絡延遲,優化重傳策略 。
4. 擁塞控制
1. 慢開始(Slow Start):在連接建立初期,發送方將擁塞窗口(Congestion Window,簡稱 cwnd)初始化為一個最大段大小(MSS),然后每收到一個 ACK,就將擁塞窗口增加一個 MSS。這樣,擁塞窗口呈指數增長,快速探測網絡的承載能力。
2. 擁塞避免(Congestion Avoidance):當擁塞窗口增長到慢開始門限(ssthresh)時,進入擁塞避免階段。在這個階段,發送方每收到一個 ACK,就將擁塞窗口增加 1/cwnd 個 MSS,使擁塞窗口線性增長,避免網絡擁塞。
3. 快重傳(Fast Retransmit):當接收方連續收到三個相同的 ACK 時,發送方會立即重傳丟失的數據段,而不需要等待定時器超時。這可以快速恢復丟失的數據,減少數據傳輸的延遲。
4. 快恢復(Fast Recovery):在快重傳之后,發送方將慢開始門限設置為當前擁塞窗口的一半,然后將擁塞窗口設置為慢開始門限加上三個重復 ACK 所確認的數據量,接著進入擁塞避免階段,而不是重新進入慢開始階段。這樣可以更快地恢復數據傳輸,提高網絡的利用率。
四、流量控制
1. 滑動窗口工作機制
- 接收窗口(RWND):接收方通過ACK報文中的窗口字段告知剩余緩沖區大小。例如,RWND=8000表示當前可接收8000字節數據 27。
- 零窗口探測:若接收方緩沖區滿(RWND=0),發送方啟動持續計時器,定期發送1字節探測包,檢測窗口恢復狀態 27。
- 窗口縮放選項:通過TCP選項擴展窗口字段位數(從16位至30位),支持高帶寬網絡的大窗口傳輸。
2. 流量控制的關鍵問題與解決
- 糊涂窗口綜合征(SWS)
-
- 發送端SWS:Nagle算法解決小數據包問題,規則如下:
if 有新數據待發送: if 窗口大小 ≥ MSS 且 數據量 ≥ MSS: 立即發送 elif 有未確認數據: 緩存數據等待ACK else: 立即發送
此算法在高延遲場景可能導致小數據等待,可通過TCP_NODELAY
選項 禁用
-
- 接收端SWS:接收方在緩沖區不足時直接通告RWND=0,強制發送方暫停,待緩沖區清空后通過探測包恢復 。
3. 擁塞控制與流量控制的協同
- 擁塞窗口(CWND):根據網絡擁塞狀態動態調整,通過慢啟動(指數增長)和擁塞避免(線性增長)平衡帶寬利用率 。
- 全局平衡:最終發送速率受
SWND = min(RWND, CWND)
限制,同時避免接收方溢出和網絡擁塞。
五、TCP報文格式
頭部結構(20~60字節)
字段 | 長度 | 說明 |
源端口/目的端口 | 16位 | 標識應用程序(如HTTP=80) |
序列號(SEQ) | 32位 | 數據包首字節的全局位置 |
確認號(ACK) | 32位 | 期望接收的下一個字節序號(僅當ACK=1時有效) |
數據偏移 | 4位 | 首部長度(以4字節為單位,最大60字節) |
控制標志 | 9位 | SYN(連接請求)、ACK(確認)、FIN(終止)、RST(重置)、PSH(急迫推送) |
窗口大小 | 16位 | 接收方可用緩沖區大小(流量控制關鍵參數) |
校驗和 | 16位 | 驗證數據完整性 |
緊急指針 | 16位 | 標識緊急數據位置(僅當URG=1時有效) 。 |