【Net】TCP粘包與半包

文章目錄

  • TCP粘包與半包
    • 1 背景
    • 2 粘包(packet stick)
    • 3 半包(packet split)
    • 4 為什么會出現粘包/半包?
    • 5 如何解決?
    • 6 示例
    • 7 總結

TCP粘包與半包

在網絡編程中,粘包半包問題是常見的 TCP 協議特有問題,尤其在基于流的傳輸協議中(如 TCP),它們常導致接收端無法正確還原發送端原本的一條條消息。


1 背景

TCP 是“字節流”協議,不保留消息邊界,它只是一個字節流協議,只保證字節的順序和完整性,但不關心應用層每條消息的邊界。這就導致了“粘包”和“半包”的出現。


2 粘包(packet stick)

定義多條數據包被粘在一起,接收端一次接收到了多條消息數據。

舉例:

客戶端連續發送兩條消息:

[hello][world]

由于 TCP 是流式協議,可能在接收端變成:

[helloworld]

此時接收端無法確定 “hello” 和 “world” 的邊界。


3 半包(packet split)

定義一條完整的數據被拆成了幾部分接收,接收端一次只能收到其中的一部分。

舉例:

客戶端發送一條 10 字節的消息:

[helloworld]

可能接收端第一次 recv 只收到:

[hello]

下一次再收到:

[world]

也就是說,一條消息被拆成了“半包”。


4 為什么會出現粘包/半包?

  • TCP 特性導致:
    1. TCP 是字節流,不維護消息邊界;
    2. Nagle 算法 會將小包合并發送(導致粘包);
    3. 接收端 buffer 緩沖區大小不確定,一次 read/recv 可能讀不到完整數據(導致半包);
    4. 操作系統的發送/接收策略 也會影響包的合并與拆分。

5 如何解決?

  • 通用思路:在應用層實現消息邊界的識別機制

    以下幾種常見方案可以避免粘包/半包問題:

    1. 定長協議

      • 每條消息固定長度(例如每條消息都是 128 字節)。
      • 優點:實現簡單;
      • 缺點:浪費帶寬,不適用于變長消息。
    2. 添加分隔符

      • 每條消息結尾加特定分隔符(如 "\r\n")。
      • 接收端通過查找分隔符來拆分消息;
      • 缺點:消息內容中不能出現分隔符。
    3. 長度前綴協議(最常用)

      • 每條消息前加一個固定長度的字段表示消息體長度(如 4 字節整數):

        [4字節長度][消息體]
        

        示例:

        [00000005][hello]
        [00000005][world]
        
        • 接收端讀取前 4 字節判斷消息長度,再讀取對應長度的消息體,精確拆包。

6 示例

C++ 實現的長度前綴協議收發邏輯示例,適用于基于 TCP 的客戶端或服務器程序,用于解決粘包/半包問題。


  • 協議格式
[4字節消息長度][消息體內容]
- 消息長度為 uint32_t(網絡字節序)

  • 核心發送/接收邏輯

發送端邏輯(附加長度前綴)

#include <arpa/inet.h> // htonl
#include <string>
#include <unistd.h>    // writebool sendMessage(int sockfd, const std::string& message) {uint32_t len = htonl(message.size()); // 轉為網絡字節序std::string packet;packet.append(reinterpret_cast<const char*>(&len), sizeof(len)); // 4字節長度packet.append(message); // 實際消息體size_t totalSent = 0;while (totalSent < packet.size()) {ssize_t sent = write(sockfd, packet.data() + totalSent, packet.size() - totalSent);if (sent <= 0) return false;totalSent += sent;}return true;
}

接收端邏輯(支持粘包/半包)

#include <arpa/inet.h> // ntohl
#include <unistd.h>    // read
#include <vector>
#include <string>bool recvExact(int sockfd, void* buffer, size_t length) {size_t total = 0;while (total < length) {ssize_t n = read(sockfd, (char*)buffer + total, length - total);if (n <= 0) return false; // 連接關閉或出錯total += n;}return true;
}bool recvMessage(int sockfd, std::string& outMessage) {uint32_t len_net;if (!recvExact(sockfd, &len_net, sizeof(len_net))) return false;uint32_t len = ntohl(len_net);if (len > 10 * 1024 * 1024) return false; // 限制最大消息長度,防止攻擊std::vector<char> buffer(len);if (!recvExact(sockfd, buffer.data(), len)) return false;outMessage.assign(buffer.begin(), buffer.end());return true;
}

客戶端完整用法

std::string msg = "hello world";
sendMessage(sockfd, msg);std::string received;
if (recvMessage(sockfd, received)) {std::cout << "Received: " << received << std::endl;
}

說明與擴展建議

項目說明
字節序使用 htonl/ntohl 保證跨平臺兼容
粘包支持多條消息合并也能正確拆分
半包支持recvExact 保證完整讀取
安全性應添加最大長度檢查,防止惡意攻擊
異步擴展可結合 epoll 實現非阻塞版本

7 總結

問題表現原因解決方式
--------
粘包多條消息合并TCP 合并包定長、分隔符、長度前綴
半包一條消息被拆開TCP 拆包接收端維護 buffer,支持多次接收拼接

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/82189.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/82189.shtml
英文地址,請注明出處:http://en.pswp.cn/web/82189.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Leetcode 3566. Partition Array into Two Equal Product Subsets

Leetcode 3566. Partition Array into Two Equal Product Subsets 1. 解題思路2. 代碼實現 題目鏈接&#xff1a;3566. Partition Array into Two Equal Product Subsets 1. 解題思路 這一題我的實現還是比較暴力的&#xff0c;首先顯而易見的&#xff0c;若要滿足題目要求&…

QT中更新或添加組件時出現“”qt操作至少需要一個處于啟用狀態的有效資料檔案庫“解決方法”

在MaintenanceTool.exe中點擊下一步 第一個&#xff1a; 第二個&#xff1a; 第三個&#xff1a; 以上任意一個放入資料庫中

52. N-Queens II

題目描述 52. N-Queens II 回溯法 這道題與第51題是一樣的。51. N-Queens-CSDN博客 class Solution {int columns; //從低位到高位起算&#xff0c;第i位為0表示棋盤第i列可以放置皇后&#xff0c;第i位為1表示棋盤第i列不能放置皇后//邊長為n的棋盤分別有2n-1條正斜線和反…

解鎖AI智能Agent的“風格基因”

從“黑箱”到“智能Agent”:LangChain的架構哲學革新 在LangChain出現之前,開發者直接調用LLM API的方式,充滿了“黑箱”操作的挑戰: 緊耦合的業務邏輯與模型調用: 所有的業務邏輯、API調用、記憶管理、錯誤處理等都可能混雜在同一個代碼塊中。這導致代碼脆弱、難以測試,…

大數據運維過程中常見的一些操作

大數據運維是確保大數據系統穩定運行、高效處理數據的關鍵環節。以下是大數據運維過程中常見的一些操作和任務: 1. 集群部署與配置 基礎設施搭建:部署服務器、網絡設備、存儲系統,配置虛擬化環境(如 Docker、Kubernetes)。分布式系統安裝:安裝 Hadoop、Spark、Hive、Kaf…

STM32中,如何理解看門狗

在STM32微控制器中&#xff0c;看門狗&#xff08;Watchdog&#xff09;是一種硬件計時器&#xff0c;用于監控系統運行狀態&#xff0c;防止軟件死鎖或跑飛。其核心機制是&#xff1a;系統需定期“喂狗”&#xff08;復位看門狗計數器&#xff09;&#xff0c;若未及時喂狗&am…

[AI算法] LLM中的gradient checkpoint機制

文章目錄 什么是gradient checkpoint原理使用場景 注意事項 什么是gradient checkpoint gradient checkpoint是一種優化深度學習模型內存使用的技術&#xff0c;尤其在訓練大型模型時非常有用。它通過犧牲計算時間為代價來減少顯存占用。大多數情況下&#xff0c;transformers…

船舶二階非線性響應方程的EKF與UKF參數辨識

船舶二階非線性響應方程的EKF與UKF參數辨識 本文將詳細闡述使用Python實現擴展卡爾曼濾波(EKF)和無跡卡爾曼濾波(UKF)對船舶二階非線性響應方程進行參數辨識的過程。全文包含理論推導、算法實現、仿真驗證及結果分析。—### 1. 船舶二階非線性響應方程建模船舶運動可表示為&am…

【ARM AMBA APB 入門 1.1 -- APB 讀寫寄存器 RTL 實現】

請閱讀【ARM AMBA 總線 文章專欄導讀】 文章目錄 APB 寄存器訪問APB 讀寄存器 RTL 代碼實現APB 寫寄存器 RTL 代碼實現 APB 寄存器訪問 APB 讀寄存器 RTL 代碼實現 APB 總線讀寄存器操作代碼實現&#xff1a; wire [31:0] SOC_PLL_CFG_REG; wire [31:0] SOC_PLL_LOCK_REG; wi…

C++修煉:位圖和布隆過濾器

Hello大家好&#xff01;很高興我們又見面啦&#xff01;給生活添點passion&#xff0c;開始今天的編程之路&#xff01; 我的博客&#xff1a;<但凡. 我的專欄&#xff1a;《編程之路》、《數據結構與算法之美》、《題海拾貝》、《C修煉之路》 1、引言 在計算機科學…

Java大廠后端技術棧故障排查實戰:Spring Boot、Redis、Kafka、JVM典型問題與解決方案

Java大廠后端技術棧故障排查實戰&#xff1a;Spring Boot、Redis、Kafka、JVM典型問題與解決方案 引言 在互聯網大廠&#xff0c;Java后端系統往往承載著高并發、高可用和復雜業務需求。系統架構日益復雜&#xff0c;涵蓋微服務、緩存、消息隊列、數據庫等多種組件&#xff0…

交叉編譯tcpdump工具

1.導出交叉編譯工具鏈 export PATH$PATH:/opt/rockchip/gcc-linaro-6.3.1-2017.05-x86_64_arm-linux-gnueabihf/bin 下載源碼包libpcap-1.10.5&#xff0c;配置、并編譯安裝。 github倉庫地址 ./configure --hostarm-linux CCarm-linux-gnueabihf-gcc --prefix$PWD/install …

Pytest Fixture 是什么?

Fixture 是什么&#xff1f; Fixture 是 Pytest 測試框架的核心功能之一&#xff0c;用于為測試函數提供所需的依賴資源或環境。它的核心目標是&#xff1a; ? 提供測試數據&#xff08;如模擬對象、數據庫記錄&#xff09; ? 初始化系統狀態&#xff08;如配置、臨時文件&a…

【深度剖析】流處理系統性能優化:解決維表JOIN、數據傾斜與數據膨脹問題

目錄 前言:為什么你的流處理作業總是慢? 一、維表JOIN優化:從普通連接到高性能查詢 1.1 時態表的雙面性 1.2 Lookup Join 優化 1.3 多表JOIN優化策略 二、數據傾斜:單分區也會遇到的隱形殺手 2.1 單分區數據傾斜 2.2 熱點鍵打散技術 2.3 時間窗口預聚合 三、數據…

Codeforces Round 1028 (Div. 2)(ABC)

A. Gellyfish and Tricolor Pansy 翻譯&#xff1a; 水母和小花在玩一個叫 “決斗 ”的游戲。 水母有 a HP&#xff0c;花花有 b HP。 它們各有一個騎士。水母的騎士有 c HP&#xff0c;而花花的騎士有 d HP。 他們將進行一輪游戲&#xff0c;直到其中一方獲勝。對于 k1、2、.…

數字創新智慧園區建設及運維方案

該文檔是 “數字創新智慧園區” 建設及運維方案,指出傳統產業園區存在管理粗放等問題,“數字創新園區” 通過大數據、AI、物聯網、云計算等數字化技術,旨在提升園區產業服務、運營管理水平,增強競爭力,實現綠色節能、高效管理等目標。建設內容包括智能設施、核心支撐平臺、…

緩存一致性協議的影響

在操作系統中&#xff0c;線程切換相比進程切換更輕量級的關鍵原因之一是 緩存&#xff08;Cache&#xff09;的有效性&#xff0c;尤其是對 CPU 緩存&#xff08;如 L1/L2/L3&#xff09;和 TLB&#xff08;Translation Lookaside Buffer&#xff09;的影響。以下從緩存角度詳…

六月一日python-AI代碼

python 運行 import turtle as t # 導入turtle庫并簡稱為t&#xff0c;用于圖形繪制 import random # 導入random庫&#xff0c;用于隨機數生成t.delay(0) # 設置繪圖延遲為0&#xff0c;加快繪圖速度 colors ["red", "blue", "gr…

58、辣椒種植學習

辣椒&#xff08;學名&#xff1a;Capsicum annuum&#xff09;屬于茄科辣椒屬&#xff0c;是一種重要的蔬菜兼調味作物&#xff0c;具有較高的經濟價值和營養價值。其果實富含維生素C、辣椒素等成分&#xff0c;既可鮮食&#xff0c;也可加工成干辣椒、辣椒粉、辣椒醬等產品&a…

C語言進階--程序的編譯(預處理動作)+鏈接

1.程序的翻譯環境和執行環境 在ANSI C標準的任何一種實現中&#xff0c;存在兩種不同的環境。 第一種是翻譯環境&#xff1a;將源代碼轉換為可執行的機器指令&#xff08;0/1&#xff09;; 第二種是執行環境&#xff1a;用于實際執行代碼。 2.詳解編譯鏈接 2.1翻譯環境 程…