定义一个TCP接收端粘包处理的函数TcpReadPkg,将每次tcp接收的数据传入;
函数第三个参数all_buffer在外部定义后传入,需要保证只被创建一次;自定义的数据结构ByteArray在文章后部;
函数内部,FRAMEHEADER是约定好的头;
注意:大家参考我这里的函数处理的时候按照自己的报文格式处理,此处我需要处理的每帧数据格式如下:
|-- 2byte head --|-- 2byte 其他 --|-- 2byte length(描述data大小)--|-- data --|-- 4byte 其他 --|
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;
}
自定义的一个数据结构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;
};