C++中TCP粘包分包处理

一 现象:

粘包:

A机器发出2包数据,B机器把2包数据作为一次收到,此时2包数据粘在一起。

分包:

A机器发送1包数据,B机器分为两次收到这包数据,此时,这1报数据分为2次被B机器收到。

二 产生原因:

当服务端和客户端用到TCP通信时,可能会有以下场景(1)网络有延迟、(2)客户端频繁发送的数据包给服务端,(3)TCP自身机制(需要等自己缓冲区满后,才发送一包数据),由于这些原因会导致粘包,服务端一次收到的数据中包含多个数据包,此时就得分包处理数据。

三 处理粘包分包代码:

(1)协议:

C++中TCP粘包分包处理

(2)代码:

#include "stdafx.h"
#include"windows.h"

#include<iostream>

#define CHONG_QING_SIX_LOCK_FRAME_MAX_LENGTH        4096
#define CHONG_QING_SIX_LOCK_DATA_HEADER_LENGTH      6

int RecvData()
{
    DWORD recv_len = 0;
    int dataLength = 0;
    int sumDataLength = 0;
    int nRemainSize = 0;
    int lastPos = 0;
    BYTE recvbuf[CHONG_QING_SIX_LOCK_FRAME_MAX_LENGTH], databuf[CHONG_QING_SIX_LOCK_FRAME_MAX_LENGTH];
    char oneFrameData[1024];

    memset(recvbuf, 0, sizeof(recvbuf));        
    memset(databuf, 0, sizeof(databuf));        

    //收到服务端消息
    //接受数据,处理粘包,拆分包
    recv_len = (int)recv(m_Socket, (char *)recvbuf, CHONG_QING_SIX_LOCK_FRAME_MAX_LENGTH, 0);
    if (recv_len > 0)
    {
        memcpy(databuf + lastPos, recvbuf, recv_len);
        lastPos += recv_len;
        //判断消息缓冲区的数据长度大于消息头
        while (lastPos >= CHONG_QING_SIX_LOCK_DATA_HEADER_LENGTH)
        {
            //包头做判断,如果包头错误,收到的数据全部清空
            if (databuf[0] == 0xEF && databuf[1] == 0xEF && databuf[2] == 0xEF && databuf[3] == 0xEF)
            {
                dataLength = MAKEWORD(databuf[4], databuf[5]);
                sumDataLength = CHONG_QING_SIX_LOCK_DATA_HEADER_LENGTH + dataLength + 6;
                //判断消息缓冲区的数据长度大于消息体
                if (lastPos >= sumDataLength)
                {
                    //CRC校验
                    if (CheckSum((byte *)databuf, dataLength + CHONG_QING_SIX_LOCK_DATA_HEADER_LENGTH + 2))
                    {
                        memcpy(oneFrameData, databuf, sumDataLength);
                        //处理数据
                        DealData(oneFrameData);
                        //剩余未处理消息缓冲区数据的长度
                        nRemainSize = lastPos - sumDataLength;
                        //将未处理的数据前移
                        if (nRemainSize > 0)
                        {
                            memcpy(databuf, databuf + (dataLength + CHONG_QING_SIX_LOCK_DATA_HEADER_LENGTH + 6), nRemainSize);
                            lastPos = nRemainSize;
                        }
                    }
                    else
                    {
                        if (nRemainSize > 0)
                        {
                            memcpy(databuf, databuf + sumDataLength, nRemainSize);
                        }

                        lastPos = nRemainSize;
                    }
                }
                else
                {
                    break;
                }
            }
            else      //寻找下一个包头
            {
                BOOL isFind = FALSE;
                int nFindStart = 0;
                for (int k = 1; k < lastPos; k++)
                {
                    if (databuf[k] == 0xEF && databuf[k + 1] == 0xEF && databuf[k + 2] == 0xEF && databuf[k + 3] == 0xEF)
                    {
                        nFindStart = k;
                        isFind = TRUE;
                        break;
                    }
                }
                if (isFind == TRUE)
                {
                    memcpy(databuf, databuf + nFindStart, lastPos - nFindStart);

                    lastPos = lastPos - nFindStart;
                }
                else
                {
                    memset(databuf, 0, sizeof(databuf));
                    lastPos = 0;
                    break;
                }
            }
        }
    }
    return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{


    system("pause");
    return 0;
}

四 对以上代码处理流程解释:

1)可以看到以上代码分为2个缓冲区,第一个只负责接收数据,第二个负责处理数据。

2)当服务端收到一包数据时,2种情况时,将处理数据的缓冲区的数据全部清空,(1)当出现包头验证错误,(2)CRC校验失败。

3)当接受到的数据长度大于包头,但是不大于整个消息体的长度时,保存前面接收的数据后,跳出while循环,继续接受数据,

4)当接收到的数据是多包数据时,它会一直在while循环里面处理数据,直到把每一包数据都分开并处理完后跳出。

原文链接: https://www.cnblogs.com/zwj-199306231519/p/13699982.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/203006

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月12日 下午9:21
下一篇 2023年2月12日 下午9:21

相关推荐