1. TCP頭部結構
TCP頭部通常為20字節(不含可選字段),每個字段占據固定的字節位置。以下是TCP頭部的結構,按字節位置逐一說明:
0 1 2 30 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Port | Destination Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Acknowledgment Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data | |U|A|P|R|S|F| |
| Offset| Reserved |R|C|S|S|Y|I| Window |
| | |G|K|H|T|N|N| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Checksum | Urgent Pointer |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options (if Data Offset > 5) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
字段詳解(按字節位置)
-
源端口(Source Port, 2字節,0-1字節)
- 作用:標識發送端的端口號,用于區分同一主機上的不同應用。
- 值:16位無符號整數(0-65535)。
- DPDK相關:在DPDK中,解析或構造TCP包時,需從
rte_mbuf
的包數據中提取或設置該字段。
-
目的端口(Destination Port, 2字節,2-3字節)
- 作用:標識接收端的端口號。
- 值:同源端口,16位無符號整數。
- DPDK相關:常與源端口一起用于五元組(源IP、目的IP、協議、源端口、目的端口)進行連接跟蹤。
-
序列號(Sequence Number, 4字節,4-7字節)
- 作用:標識發送的數據字節流的起始位置,用于確保數據按序到達和檢測丟失。
- 值:32位無符號整數,初始值在SYN包中隨機生成。
- DPDK相關:在用戶態協議棧中,需手動維護序列號遞增邏輯。
-
確認號(Acknowledgment Number, 4字節,8-11字節)
- 作用:表示接收端期望接收的下一個字節的序列號,用于確認已接收的數據。
- 值:32位無符號整數,僅當ACK標志置位時有效。
- DPDK相關:在ACK包處理中,需檢查確認號以驗證數據傳輸狀態。
-
數據偏移(Data Offset, 4位,12字節高4位)
- 作用:表示TCP頭部長度(以4字節為單位),因為頭部可能包含可選字段。
- 值:范圍5-15(對應20-60字節)。
- DPDK相關:解析TCP包時,需根據此字段確定頭部長度以定位數據部分。
-
保留位(Reserved, 6位,12字節次高6位)
- 作用:保留供未來使用,當前必須置0。
- DPDK相關:通常忽略,但需確保構造包時置0。
-
標志位(Flags, 6位,12字節低6位)
- 作用:控制TCP連接狀態和數據傳輸行為,詳細見下文“標志位詳解”。
- 值:包括URG、ACK、PSH、RST、SYN、FIN六個標志。
-
窗口大小(Window, 2字節,13-14字節)
- 作用:表示接收端的接收緩沖區大小,用于流量控制。
- 值:16位無符號整數(0-65535字節),可通過窗口擴展選項放大。
- DPDK相關:在高性能場景中,需根據窗口大小動態調整發送速率。
-
校驗和(Checksum, 2字節,15-16字節)
- 作用:驗證TCP頭部、數據及偽頭部的完整性。
- 值:16位校驗和,計算方法見前文。
- DPDK相關:可通過DPDK的
rte_ipv4_udptcp_cksum
計算,或使用網卡硬件卸載(如PKT_TX_TCP_CKSUM
)。
-
緊急指針(Urgent Pointer, 2字節,17-18字節)
- 作用:當URG標志置位時,指示緊急數據的偏移量。
- 值:16位無符號整數,指向緊急數據的最后一個字節。
- DPDK相關:緊急數據在現代應用中較少使用,通常忽略。
-
選項(Options, 可變長度,19字節起,若Data Offset > 5)
- 作用:提供擴展功能,如最大段大小(MSS)、窗口擴展、時間戳等。
- 長度:0-40字節,需4字節對齊。
- DPDK相關:在構造或解析包時,需根據Data Offset處理選項字段。
2. TCP標志位(Flags)的名稱由來和用法
TCP頭部中的6個標志位(URG、ACK、PSH、RST、SYN、FIN)位于12字節的低6位,每個標志位占1位。以下是它們的名稱由來和具體用法:
-
URG(Urgent, 緊急標志)
- 名稱由來:表示數據包中包含緊急數據,需要優先處理。“Urgent”反映了其緊急優先級。
- 用法:
- 當URG=1時,緊急指針字段有效,指示緊急數據的結束位置。
- 緊急數據應被立即處理,通常用于中斷或控制場景(如Telnet的Ctrl+C)。
- 現代場景:很少使用,部分協議棧甚至忽略此標志。
- DPDK相關:在DPDK中,URG標志處理較少,需檢查
struct rte_tcp_hdr
的tcp_flags
字段。
-
ACK(Acknowledgment, 確認標志)
- 名稱由來:表示確認已接收的數據。“Acknowledgment”指接收端對發送端數據的確認。
- 用法:
- 當ACK=1時,確認號字段有效,表示接收端期望的下一個字節序列號。
- 用于確認數據接收,驅動TCP的可靠傳輸機制。
- 在三次握手中,第二次和第三次握手包會設置ACK=1。
- DPDK相關:在用戶態協議棧中,需檢查ACK標志以處理確認邏輯。
-
PSH(Push, 推送標志)
- 名稱由來:指示接收端立即將數據“推送”到應用層,而不等待緩沖區填滿。“Push”強調數據盡快交付。
- 用法:
- 當PSH=1時,提示接收端盡快將數據交給上層應用,而不是緩存。
- 常用于實時性要求高的場景(如交互式應用)。
- 現代場景:許多協議棧默認立即交付,PSH作用減少。
- DPDK相關:在DPDK中,PSH標志可用于優化數據交付邏輯。
-
RST(Reset, 重置標志)
- 名稱由來:表示重置連接,通常用于異常終止。“Reset”反映了其強制中斷連接的角色。
- 用法:
- 當RST=1時,表示連接異常或拒絕(如端口未開放、連接不可用)。
- 用于快速關閉連接或拒絕非法請求。
- DPDK相關:在DPDK中,需檢測RST標志以處理連接錯誤或終止狀態。
-
SYN(Synchronize, 同步標志)
- 名稱由來:用于同步通信雙方的序列號。“Synchronize”反映了其初始化序列號的作用。
- 用法:
- 當SYN=1時,表示發起TCP連接,攜帶初始序列號(ISN)。
- 用于三次握手的第一步(客戶端發送SYN)和第二步(服務器發送SYN+ACK)。
- DPDK相關:在DPDK中,構造SYN包需設置
tcp_flags
中的SYN位,并初始化序列號。
-
FIN(Finish, 結束標志)
- 名稱由來:表示發送端已完成數據發送,請求關閉連接。“Finish”反映了其終止連接的含義。
- 用法:
- 當FIN=1時,表示發送端無更多數據要發送,請求關閉連接。
- 用于四次揮手中的第一步和第三步,完成連接的正常關閉。
- DPDK相關:在DPDK中,需處理FIN標志以管理連接關閉流程。
3. DPDK中的TCP頭部處理
在DPDK開發中,TCP頭部的解析和構造是常見操作,以下是相關要點:
- 頭部解析:通過
rte_mbuf
訪問數據包,使用struct rte_tcp_hdr
結構解析TCP頭部字段。例如:struct rte_tcp_hdr *tcp_hdr = rte_pktmbuf_mtod_offset(mbuf, struct rte_tcp_hdr *, ip_hdr_len); uint8_t tcp_flags = tcp_hdr->tcp_flags; // 獲取標志位
- 標志位操作:DPDK提供了宏(如
RTE_TCP_SYN_FLAG
、RTE_TCP_ACK_FLAG
)來檢查或設置標志位。例如:if (tcp_hdr->tcp_flags & RTE_TCP_SYN_FLAG) {// 處理SYN包 }
- 校驗和處理:可使用
rte_ipv4_udptcp_cksum
計算校驗和,或啟用網卡硬件卸載(PKT_TX_TCP_CKSUM
)。 - 選項處理:根據
data_off
字段(右移4位得到頭部長度)解析選項字段,需注意字節對齊。
4. 總結
- TCP頭部結構:共20字節(無選項),包括源/目的端口、序列號、確認號、數據偏移、標志位、窗口大小、校驗和、緊急指針等字段。
- 標志位由來與用法:
- URG:緊急數據,優先處理(少用)。
- ACK:確認接收,驅動可靠傳輸。
- PSH:推送數據,加快交付。
- RST:重置連接,處理異常。
- SYN:同步序列號,建立連接。
- FIN:結束連接,正常關閉。
- DPDK相關:在DPDK中,需解析/構造TCP頭部,處理標志位以實現連接管理,結合硬件卸載優化性能。
值得注意的是:
在 TCP 的三次握手過程中,第二次握手(即服務端回復 SYN+ACK 報文)中的 ACK 通常會是對方初始序列號加 1。原因是,TCP 協議中 SYN 和 FIN 這類控制位雖然不攜帶有效數據,但它們本身會占用一個序列號位置,也就是說 SYN 報文等價于“長度為 1 的虛擬數據”。
因此,客戶端第一次發送的 SYN 報文中若使用初始序列號 x,服務端在回復 ACK 時就必須設置為 x+1,表示已經“收到”了這個 SYN。
相反,在正常的數據通信過程中,一個不攜帶任何數據的 ACK 報文(例如僅用于確認收到某段數據)不會額外消耗序列號。它只是對前面數據的確認,因此 ACK 值不會額外加 1,除非前一個報文中確實包含了數據或 FIN、SYN 這類控制位。
所以,并不是“ACK 就一定要 +1”,而是“如果前一個報文包含了 SYN、FIN 或數據,就要按其長度加 1 或加對應長度”。三次握手中之所以出現 +1,只是因為 SYN 報文本身占了一個序號位置。這個現象容易被誤解為“ACK 報文默認要加 1”,實質上是對 TCP 序列號含義的不準確理解。