TCP通信防粘包处理

1.定义一个TCP接收端粘包处理的函数TcpReadPkg(),将每次TCP套接字接收的数据传入;

2.函数第三个参数all_buffer在外部定义后传入,需要保证只被创建一次;

3.开始先自定义的数据结构ByteArray

4.函数内部,FRAMEHEADER是约定好的头;

注意:大家参考我这里的函数处理的时候按照自己的报文格式处理,此处我需要处理的每帧数据格式如下:

|-- 2byte head --|-- 2byte 其他 --|-- 2byte length(描述data大小)--|-- data --|-- 4byte 其他 --|

自定义的一个数据结构ByteArray,方便处理接收到的内容:

//字节数组
class ByteArray
{
public:
	ByteArray(int max_len = 204800)
	{
		this->max_len = max_len;
		buffer = new char[max_len];
		size = 0;
	}
	~ByteArray()
	{
		delete buffer;
	}
	//大小
	int Size()
	{
		return size;
	}
	//数据
	char* Data()
	{
		return buffer;
	}
	//添加
	void append(char* input_buffer, int len)
	{
		if (size + len > max_len) return;
		memcpy(buffer + size, input_buffer, len);
		size += len;
	}
	//删除前面一截
	void front_pop(int front_pop_len)
	{
		if (size < front_pop_len) return;
		char* temp = new char[max_len];
		memcpy(temp, buffer + front_pop_len, size - front_pop_len);
		delete buffer;
		buffer = temp;
		size -= front_pop_len;
	}
    //清空
    void clear()
    {
	    size = 0;
    }
	//查找
	int find(char* find_buffer, int len)
	{
		if (len > size || len < 1) return -1;
		int index = -1;
		for (int i = 0; i < size - len + 1; i++)
		{
			for (int j = 0; j < len; j++)
			{
				if (buffer[i + j] != find_buffer[j])
					break;
				if (j == len - 1)
					return i;
			}
		}
		return index;
	}
private:
	int max_len;
	char* buffer;
	int size;
}

 TCP接收端粘包处理的函数TcpReadPkg()的实现


int TcpReadPkg(char* read_buffer, int read_len, ByteArray &all_buffer)//tcp防粘包解包
{
    all_buffer.append(read_buffer, read_len);//追加数据进自定义缓冲区AllBuffer
    Ushort head = FRAMEHEADER;
    int headIndex = all_buffer.find((char*)&head, 2);//报文头位置,找不到返回-1
    if(-1 == headIndex && all_buffer.Size() >= 6)//整个AllBuffer无报文头,清空AllBuffer防止无效信息累积
        all_buffer.clear();
    Ushort length = 0;//包头报文长度信息
    while(-1 != headIndex)//数据中有报文头就循环
    {
        all_buffer.front_pop(headIndex);//去掉报头前的
        if(all_buffer.Size() < 6)//报头后长度信息不完整,下次接收数据再处理
            break;
        memcpy(&length, all_buffer.Data() + 4, 2);//读取长度信息,2字节length
        if(length > 50000)//根据需求,这里不会大于50000
        {
            std::cout << "[Error]  length > 50000,  length = " << length << std::endl;
            all_buffer.front_pop(6);//去掉整个报头前的
            length = 0;
        }
        if(all_buffer.Size() >= length + 6 + 4 && length > 0)//长度足够
        {
            std::cout << "all_buffer.size = " << all_buffer.Size() << ", length = " << length << std::endl;
            //有效data在这里
            int actual_length = length + 6 + 4;
            //all_buffer.Data()就是解出来的一包数据首地址,包括头尾
            //在这里处理解包的数据
            all_buffer.front_pop(length + 6 + 4);//去掉已获取的部分
        }
        else//长度不够,下次接收数据再处理
             break;
        headIndex = all_buffer.find((char*)&head, 2);//刷新报文头位置,找不到返回-1
    }
    return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值