C++面试5_ TCP 粘包2(工业级)

复制代码
//接收端
#pragma pack(1)
struct protocol_head_
{
    int MainMsgID; // 主消息ID
    int SubMsgID; // 子消息ID
    int DataLen; // 数据长度,不包含头
    int Reserve1; // 预留字段1
};
复制代码
void Test::recvData()
{
    LOG_DEBUGGING("启动接收数据线程");
    int headLen = sizeof(protocol_head_);
    char *pHeadData = new char[headLen];
    char *pData = nullptr;
    int npDataLen = 0;
    while (m_bInited)
    {
        if (!m_bConnected)
        {
            Sleep(1);
            continue;
        }
        int nRecvLen = 0;
        memset(pHeadData, 0, headLen);

        // 读取头数据,先收固定长度包头
        while (1)
        {

            int len = ::recv(m_s, pHeadData + nRecvLen, headLen - nRecvLen, 0);

            if (len <= 0)
            {// 连接异常
                m_bConnected = false;
                break;
            }
            else
            {
                nRecvLen += len;

                if (nRecvLen >= headLen)
                {
                    break;
                }
            }
        }
        if (!m_bConnected) continue;

        nRecvLen = 0;

        protocol_head_ *pHead = (protocol_head_*)pHeadData;

        // 读取消息体,(从包头取长度)
        int bodyLen = pHead->DataLen;

        if (bodyLen < 0)
        {
            m_bConnected = false;
            continue;
        }
        if (bodyLen == 0)
        {
            continue;
        }
        else
        {
            if (pData == nullptr || headLen + bodyLen > npDataLen)
            {
                if (pData != nullptr) delete[]pData;
                pData = new char[headLen + bodyLen];
                npDataLen = headLen + bodyLen;
            }
            memcpy(pData, pHeadData, headLen);

             //再按长度收包体
            while (1)
            {
                int len = ::recv(m_s, pData + nRecvLen + headLen, bodyLen - nRecvLen, 0);
                if (len <= 0)
                {// 连接异常
                    m_bConnected = false;
                    break;
                }
                else
                {
                    nRecvLen += len;

                    if (nRecvLen >= bodyLen)
                    {
                        break;
                    }
                }
            }
            if (!m_bConnected) continue;
        }

//一包一包处理

if (pHead->MainMsgID == N_NOTIFY && pHead->SubMsgID == N_DACTYLOGRAM__INFO)

{

}

}

void Test:recvData()

{

LOG_DEBUGGING("启动接收数据线程(buffer模型)");

const int HEAD_LEN = sizeof(protocol_head_);

const int MAX_PACKET_SIZE = 1024 * 1024; // 1MB(根据业务调)

const int MAX_BUFFER_SIZE = 2 * 1024 * 1024;

std::vector<char> buffer;

buffer.reserve(64 * 1024); // 预留64KB,减少扩容

char tmp4096;

while (m_bInited)

{

if (!m_bConnected)

{

Sleep(1);

continue;

}

// ================== 1️⃣ 收数据 ==================

int len = recv(m_s, tmp, sizeof(tmp), 0);

if (len == 0)

{

LOG_DEBUGGING("socket closed by peer");

m_bConnected = false;

continue;

}

else if (len < 0)

{

int err = WSAGetLastError();

if (err == WSAEWOULDBLOCK)

{

Sleep(1);

continue;

}

LOG_DEBUGGING("recv error: %d", err);

m_bConnected = false;

continue;

}

// 写入 buffer

buffer.insert(buffer.end(), tmp, tmp + len);

// 防止buffer无限增长

if (buffer.size() > MAX_BUFFER_SIZE)

{

LOG_DEBUGGING("buffer overflow, reset connection");

m_bConnected = false;

buffer.clear();

continue;

}

// ================== 2️⃣ 解析数据 ==================

size_t offset = 0;

while (true)

{

// 2.1 不够一个包头

if (buffer.size() - offset < HEAD_LEN)

break;

// 2.2 读取头(不能直接指针长期用)

protocol_head_ head;

memcpy(&head, buffer.data() + offset, HEAD_LEN);

// ⚠️ 如果跨平台,打开这行

// head.DataLen = ntohl(head.DataLen);

int bodyLen = head.DataLen;

// 2.3 长度校验(非常关键)

if (bodyLen <= 0 || bodyLen > MAX_PACKET_SIZE)

{

LOG_DEBUGGING("invalid bodyLen=%d, disconnect", bodyLen);

m_bConnected = false;

break;

}

int totalLen = HEAD_LEN + bodyLen;

// 2.4 不够完整包

if (buffer.size() - offset < totalLen)

break;

// ================== 3️⃣ 处理完整包 ==================

char* packet = buffer.data() + offset;

protocol_head_* pHead = (protocol_head_*)packet;

// 👉 业务分发

if (pHead->MainMsgID == N_NOTIFY && pHead->SubMsgID == N_DACTYLOGRAM__INFO)

{

}

// 处理完一个包 → 偏移

offset += totalLen;

}

// ================== 4️⃣ 清理已处理数据 ==================

if (offset > 0)

{

buffer.erase(buffer.begin(), buffer.begin() + offset);

}

}

#endif

}

相关推荐
code_pgf2 小时前
C++11 / C++14 / C++17 / C++20 新特性总结
c++·c++20
魔力女仆2 小时前
分享一个 JS 鼠标跟随贪吃蛇背景库
开发语言·javascript·计算机外设
2401_894915533 小时前
GEO 搜索优化完整源码从零部署:环境配置、集群搭建全流程
开发语言·python·tcp/ip·算法·unity
麻瓜老宋3 小时前
AI开发C语言应用按步走,表达式计算器calc的第二十二步,分号赋值链式修复、TOKEN_ASSIGN
c语言·开发语言·atomcode
颜x小5 小时前
[C#] C++与c#语法对比
开发语言·c++·c#
weixin_423652135 小时前
C#使用JObject
开发语言·c#
国科安芯6 小时前
FreeRTOS RISC-V 浮点上下文切换移植:在 IAR 工程中完整保存 FPU 寄存器
java·开发语言·单片机·嵌入式硬件·算法·系统架构·risc-v
汉克老师7 小时前
GESP2026年3月认证C++八级( 第三部分编程题(2、子图最短路)精讲
c++·最短路·floyd·gesp8级
霸道流氓气质7 小时前
Java中集成Smile 技术教程:从入门到工程实践
java·开发语言
BerrySen1787 小时前
迈向 Next-Gen Java:企业级高并发架构演进与大模型 Agent 落地深度实战
java·开发语言·架构