更好閱讀體驗:《理解 TCP 和 UDP》— By Gitbook
TCP 是面向字節流的,但傳送的數據單元卻是報文段。
什么是報文?
例如一個 100kb 的 HTML 文檔需要傳送到另外一臺計算機,并不會整個文檔直接傳送過去,可能會切割成幾個部分,比如四個分別為 25kb 的數據段。
而每個數據段再加上一個 TCP 首部,就組成了 TCP 報文。
一共四個 TCP 報文,發送到另外一個端。
另外一端收到數據包,然后再剔除 TCP 首部,組裝起來。
等到四個數據包都收到了,就能還原出來一個完整的 HTML 文檔了。
在 OSI 的七層協議中,第二層(數據鏈路層)的數據叫「Frame」,第三層(網絡層)上的數據叫「Packet」,第四層(傳輸層)的數據叫「Segment」。
TCP 報文 (Segment),包括首部和數據部分。
而 TCP 的全部功能都體現在它首部中各字段的作用,只有弄清 TCP 首部各字段的作用才能掌握 TCP 的工作原理。
TCP 報文段首部的前20個字節是固定的,后面有 4N 字節是根據需要而增加的。
下圖是把 TCP 報文中的首部放大來看。
TCP 的首部包括以下內容:
- 源端口 source port
- 目的端口 destination port
- 序號 sequence number
- 確認號 acknowledgment number
- 數據偏移 offset
- 保留 reserved
- 標志位 tcp flags
- 窗口大小 window size
- 檢驗和 checksum
- 緊急指針 urgent pointer
- 選項 tcp options
下面展開來描述個字段的意義和作用。
TCP 首部各字段的意義和作用
源端口和目的端口 Port
各占 2 個 字節,共 4 個字節。
用來告知主機該報文段是來自哪里以及傳送給哪個應用程序(應用程序綁定了端口)的。
進行 TCP 通訊時,客戶端通常使用系統自動選擇的臨時端口號,而服務器則使用知名服務端口號。
序號 Sequence Number
占 4 個字節。
TCP 是面向字節流的,在一個 TCP 連接中傳輸的字節流中的每個字節都按照順序編號。
例如 100 kb 的 HTML 文檔數據,一共 102400 (100 * 1024) 個字節,那么每一個字節就都有了編號,整個文檔的編號的范圍是 0 ~ 102399。
序號字段值指的是本報文段所發送的數據的第一個字節的序號。
那么 100 的 HTML 文檔分割成四個等分之后,
第一個 TCP 報文段包含的是第一個 25kb 的數據,0 ~ 25599 字節, 該報文的序號的值就是:0
第二個 TCP 報文段包含的是第二個 25kb 的數據,25600 ~ 51199 字節,該報文的序號的值就是:25600
......
根據 8 位 = 1 字節,那么 4 個字節可以表示的數值范圍:[0, 2^32],一共 2^32 (4294967296) 個序號。
序號增加到最大值的時候,下一個序號又回到了 0.
也就是說 TCP 協議可對 4GB 的數據進行編號,在一般情況下可保證當序號重復使用時,舊序號的數據早已經通過網絡到達終點或者丟失了。
確認號 Acknowledgemt Number
占 4 個字節。
表示期望收到對方下一個報文段的序號值。
TCP 的可靠性,是建立在「每一個數據報文都需要確認收到」的基礎之上的。
就是說,通訊的任何一方在收到對方的一個報文之后,都要發送一個相對應的「確認報文」,來表達確認收到。
那么,確認報文,就會包含確認號。
例如,通訊的一方收到了第一個 25kb 的報文,該報文的 序號值=0,那么就需要回復一個確認報文,其中的確認號 = 25600.
數據偏移 Offset
占 0.5 個字節 (4 位)。
這個字段實際上是指出了 TCP 報文段的首部長度 ,它指出了 TCP報文段的數據起始處 距離 TCP報文的起始處 有多遠。(注意 數據起始處 和 報文起始處 的意思)
一個數據偏移量 = 4 byte,由于 4 位二進制數能表示的最大十進制數字是 15,因此數據偏移的最大值是 60 byte,這也側面限制了 TCP 首部的最大長度。
保留 Reserved
占 0.75 個字節 (6 位)。
保留為今后使用,但目前應置為 0。
標志位 TCP Flags
標志位,一共有 6 個,分別占 1 位,共 6 位 。
每一位的值只有 0 和 1,分別表達不同意思。
緊急 URG (Urgent)
當 URG = 1 的時候,表示緊急指針(Urgent Pointer)有效。
它告訴系統此報文段中有緊急數據,應盡快傳送,而不要按原來的排隊順序來傳送。
URG 要與首部中的 緊急指針 字段配合使用。
確認 ACK (Acknowlegemt)
當 ACK = 1 的時候,確認號(Acknowledgemt Number)有效。
一般稱攜帶 ACK 標志的 TCP 報文段為「確認報文段」。
TCP 規定,在連接建立后所有傳送的報文段都必須把 ACK 設置為 1。
推送 PSH (Push)
當 PSH = 1 的時候,表示該報文段高優先級,接收方 TCP 應該盡快推送給接收應用程序,而不用等到整個 TCP 緩存都填滿了后再交付。
復位 RST (Reset)
當 RST = 1 的時候,表示 TCP 連接中出現嚴重錯誤,需要釋放并重新建立連接。
一般稱攜帶 RST 標志的 TCP 報文段為「復位報文段」。
同步 SYN (SYNchronization)
當 SYN = 1 的時候,表明這是一個請求連接報文段。
一般稱攜帶 SYN 標志的 TCP 報文段為「同步報文段」。
在 TCP 三次握手中的第一個報文就是同步報文段,在連接建立時用來同步序號。
對方若同意建立連接,則應在響應的報文段中使 SYN = 1 和 ACK = 1。
終止 FIN (Finis)
當 FIN = 1 時,表示此報文段的發送方的數據已經發送完畢,并要求釋放 TCP 連接。
一般稱攜帶 FIN 的報文段為「結束報文段」。
在 TCP 四次揮手釋放連接的時候,就會用到該標志。
窗口大小 Window Size
占 2 字節。
該字段明確指出了現在允許對方發送的數據量,它告訴對方本端的 TCP 接收緩沖區還能容納多少字節的數據,這樣對方就可以控制發送數據的速度。
窗口大小的值是指,從本報文段首部中的確認號算起,接收方目前允許對方發送的數據量。
例如,假如確認號是 701 ,窗口字段是 1000。這就表明,從 701 號算起,發送此報文段的一方還有接收 1000 (字節序號是 701 ~ 1700) 個字節的數據的接收緩存空間。
校驗和 TCP Checksum
占 2 個字節。
由發送端填充,接收端對 TCP 報文段執行 CRC 算法,以檢驗 TCP 報文段在傳輸過程中是否損壞,如果損壞這丟棄。
檢驗范圍包括首部和數據兩部分,這也是 TCP 可靠傳輸的一個重要保障。
緊急指針 Urgent Pointer
占 2 個字節。
僅在 URG = 1 時才有意義,它指出本報文段中的緊急數據的字節數。
當 URG = 1 時,發送方 TCP 就把緊急數據插入到本報文段數據的最前面,而在緊急數據后面的數據仍是普通數據。
因此,緊急指針指出了緊急數據的末尾在報文段中的位置。