TCP 報文結構
TCP 頭部?20字節(無選項),關鍵字段:
字段 | 長度(bit) | 說明 |
---|---|---|
源端口 | 16 | 發送方端口 |
目的端口 | 16 | 接收方端口 |
序列號(seq) | 32 | 數據字節的編號 |
確認號(ack) | 32 | 期望收到的下一個字節編號(ACK=1時有效) |
數據偏移 | 4 | TCP 頭部長度(單位:4字節) |
控制位 | 6 | URG 、ACK 、PSH 、RST 、SYN 、FIN |
窗口大小 | 16 | 接收方的可用緩沖區大小 |
校驗和 | 16 | 數據完整性校驗 |
緊急指針 | 16 | URG=1 ?時有效,指示緊急數據位置 |
TCP 核心特性
一、 可靠性(Reliability)
TCP 確保數據?無丟失、無重復、無錯誤、按序到達,主要依賴以下機制:
-
確認應答(ACK):接收方收到數據后,發送?ACK(Acknowledgment)?確認。
-
超時重傳(Retransmission):如果發送方未收到 ACK,會在超時后重傳數據。
-
序列號(Sequence Number):每個字節分配唯一編號,解決?亂序?和?重復?問題。
-
校驗和(Checksum):檢測數據是否損壞,若校驗失敗則丟棄。
1、確認應答
發送方和接收方之間用來確認對方是否收到信息的機制,發送應答報文的控制位的 ACK 為有效?1。如圖每次發送消息都會確認是否送達。
但是在網絡中是多變的,有可能會出現 “后發先至” 的情況存在。就如下圖所示由于每條數據報的發送路徑不一樣,會造成消息的混亂,本來要給骨干漲工資的,變成說“say you”了,為了避免出現這樣的情況,就引入了 “序號和確認序號” 。
2、序列號
它會給每一條信息編號,在接收方收到消息后在返回ACK時返回收到的序號,此時也避免了發送方不知道丟失的數據報,也可以根據這個編號在緩沖區進行排序。在下圖中假如發送方一直沒有接收到2001的應答報文,則發送方就知道1001~2000的數據丟失。然而ACK 也會丟包,發送方沒有收到ACK,那怎么知道數據到沒到呢?這就要涉及下一個特性 “超時重傳”
3、超時重傳
超時重傳是對確認應答的重要補充,主要就是針對丟包的場景。發送方沒有收到ACK有兩種情況,一種是發送的數據包丟包,一種是接收方返回的ACK丟包。
第一種情況,在沒有收到ACK超過一定時間后,就會觸發超時重傳機制,這是理所應當的。
第二種情況,也會觸發超時重傳,但是接收方已經收到一次數據,面對接收兩次數據,在操作系統維護的一個 “接收緩沖區”(內存空間)中就會根據序列號進行 “去重”,以保證接收到讀取到的數據是有序且不重復的。
萬一重傳后右沒有收到應答,則會等待更長時間后繼續重傳,直到達到重傳時間達到上限,依舊沒有成功,TCP 連接就會“重置”(涉及“復位報文”控制位RST),發送方就會單方面斷開連接。
二、連接管理(Connection-Oriented)
通信前必須先?建立連接,通信后?釋放連接:
1、三次握手(Three-Way Handshake)?
意義:
- 投?問路,驗證通信鏈路是否暢通
- 驗證通信雙方的發送能力和接收能力
- 協商關鍵信息
建立連接:
- SYN(Client → Server):
SYN=1, seq=x
(同步序列號)。 - SYN+ACK(Server → Client):
SYN=1, ACK=1, seq=y, ack=x+1
。 - ACK(Client → Server):
ACK=1, seq=x+1, ack=y+1
。
? ? ? ? ? ? ? ? Client? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?Sserver
2、四次揮手(Four-Way Handshake)?
釋放連接:
- FIN(主動方 → 被動方):
FIN=1, seq=u
。 - ACK(被動方 → 主動方):
ACK=1, ack=u+1
(半關閉狀態)。 - FIN(被動方 → 主動方):
FIN=1, seq=v
。 - ACK(主動方 → 被動方):
ACK=1, ack=v+1
(等待?2MSL?后關閉)。
TIME_WAIT
想?想,為什么是TIME_WAIT的時間是2MSL?
- MSL是TCP報?的最??存時間,因此TIME_WAIT持續存在2MSL的話
- 就能保證在兩個傳輸?向上的尚未被接收或遲到的報?段都已經消失(否則服務器?刻重啟,可能會收到來?上?個進程的遲到的數據,但是這種數據很可能是錯誤的);
- 同時也是在理論上保證最后?個報?可靠到達(假設最后?個ACK丟失,那么服務器會再重發?個FIN.這時雖然客?端的進程不在了,但是TCP連接還在,仍然可以重發LAST_ACK);
CLOSE_WAIT
?般??,對于服務器上出現?量的 CLOSE_WAIT 狀態,原因就是服務器沒有正確的關閉 socket,導致四次揮?沒有正確完成。 這是?個 BUG.只需要加上對應的close即可解決問題.
值得注意的是,在四次揮手過程中,有可能只發生三次,原因是因為TCP 有延時應答機制
三、 流量控制(Fow Control)
-
滑動窗口(Sliding Window):接收方通過?窗口大小(Window Size)?告知發送方還能接收多少數據,防止發送過快導致緩沖區溢出。
-
零窗口探測(Zero Window Probe):如果接收方窗口為0,發送方會定期發送探測包,直到窗口恢復。
1、滑動窗口
窗口的大小就是一次發送數據的多少,在一組數據發過去之后,就會等待接收方回復ACK,這就從之前的一次等待一條回復變成一次等待多條回復,大大提高了效率。在這基礎上,滑動窗口不是每次都要等到一組ACK接收到了才會發送下一組數據,而是會根據接收到的回復,立即發送下一條數據,如下圖所示此時就像一個窗口向右滑動。
2、如果出現丟包咋辦?
情況一:數據包到達,ACK 丟失
此時在滑動窗口下不用做任何處理,因為 ACK 有序列號確認規則,假如只收到 5001 的ACK 則表示 0~ 5000 的數據都已經收到。但是如果是最后一條ACK 則會觸發確認應答、超時重傳。
情況二:數據包丟失
B 反復向 A 索要沒有收到的1001 這個數據 A 感知到 B 連續多次索要1001之后就會認為 1001 丟包觸發重傳 1001.
一旦 1001-2000 數據B收到了
此時B觀察發現,自己的接受緩沖區里,已經有2001-7000 這些數據了接下來從 7001 索要即可~~
3、零窗口探測
接收端處理數據的速度是有限的.如果發送端發的太快,導致接收端的緩沖區被打滿,這個時候如果發送端繼續發送,就會造成丟包,繼?引起丟包重傳等等?系列連鎖反應.
- 接收端將??可以接收的緩沖區??放?TCP?部中的"窗???"字段,通過ACK端通知發送端;
- 窗???字段越?,說明?絡的吞吐量越?;
- 接收端?旦發現??的緩沖區快滿了,就會將窗??設置成?個更?的值通知給發送端;
- 發送端接受到這個窗?之后,就會減慢??的發送速度;
當發送方知道緩沖區剩余大小為0時,就會暫停發送,直到得知接收方緩沖區不再滿。這里的有兩種方式得知,一是接收方主動通知,二是通過發送方周期性發送的一個零窗口探測包
四、 擁塞控制(Congestion Control)
防止網絡過載,實現動態平衡的主要機制:
-
慢啟動(Slow Start):窗口從?1 MSS(最大報文段)開始,指數增長,直到?閾值(ssthresh)。
-
擁塞避免(Congestion Avoidance):窗口?線性增長,避免過快引發丟包。
-
快速重傳(Fast Retransmit):收到?3個重復ACK?時立即重傳(不等待超時)。
-
快速恢復(Fast Recovery):重傳后直接進入?擁塞避免,而非慢啟動。
五、延時應答
六、捎帶應答
七、 基于字節流(Byte Stream)
-
無消息邊界:數據被視為?連續的字節流,應用層需自行解析(如 HTTP 用?
Content-Length
?或?Transfer-Encoding: chunked
)。 -
緩沖機制:TCP 在發送端和接收端維護緩沖區,提高傳輸效率。
粘包問題
八、 全雙工通信(Full-Duplex)
-
同一連接可?同時雙向傳輸,雙方獨立維護?序列號?和?ACK。
九、異常情況
TCP vs UDP
特性 | TCP | UDP |
---|---|---|
連接方式 | 面向連接(三次握手) | 無連接 |
可靠性 | 可靠(ACK、重傳) | 不可靠 |
流量控制 | 滑動窗口 | 無 |
擁塞控制 | 復雜算法(慢啟動、擁塞避免等) | 無 |
數據順序 | 保證按序到達 | 不保證 |
頭部大小 | 20 字節(最小) | 8 字節 |
傳輸效率 | 較低(協議開銷大) | 較高 |
適用場景 | HTTP、FTP、SSH、數據庫 | DNS、視頻流、游戲、QUIC |
總結
TCP 的核心目標是?可靠傳輸,通過?連接管理、ACK、重傳、流量控制、擁塞控制?等機制實現。雖然效率不如 UDP,但適用于?要求數據完整性的場景。理解 TCP 對網絡編程、性能優化、故障排查至關重要。
本篇文章的插圖部分來自《圖解 TCP/IP》