您的位置:首页 > 新闻 > 资讯 > C++ tcp中的可变长度结构体的序列化和反序列化

C++ tcp中的可变长度结构体的序列化和反序列化

2025/1/15 18:34:02 来源:https://blog.csdn.net/weixin_45432553/article/details/140017556  浏览:    关键词:C++ tcp中的可变长度结构体的序列化和反序列化

近日,在项目里,需要对tcp传输的数据进行序列化和反序列化,有很多方法,记录下来
写在前面:使用tcp传输的时候需要注意字节对齐的问题,在以下代码中统一使用单字节对齐

//单字节对齐   写在结构体定义之上
#pragma pack(1)

第一种 QT
如果是用QT写的,结构体拿到值以后,可以使用QDataStream来进行序列化和反序列化,可以参考这个链接

struct MsgBody
{int iValue;     // 下面两个vector的sizedouble dValue;string strValue;vector<int> vStrSize;			vector<string> vStr;			//写数据到类数据成员中void write(QByteArray *data){QDataStream streamWriter(data, QIODevice::WriteOnly);streamWriter.setVersion(QDataStream::Qt_5_14);streamWriter << iValue;streamWriter << dValue;// string 需要转 QString 才能使用 << ,同时如果 string 中有中文,还需要注意当前的编码格式转换// 使用 QDataStream 序列化和反序列化不能重载 stringQString qstr = QString::fromLocal8Bit(strValue.c_str());streamWriter << qstr.toLocal8Bit();for (int i = 0; i < iValue; i++){int iTemp = vStrSize[i];streamWriter << iTemp;}for (int j = 0; j < iValue; j++){string strValue = vStr[j];QString qstrValue = QString::fromLocal8Bit(strValue.c_str());streamWriter << qstrValue.toLocal8Bit();}}//读数据到类数据成员中void read(QByteArray &data){QDataStream streamReader(&data, QIODevice::ReadOnly);streamReader.setVersion(QDataStream::Qt_4_3);streamReader >> iValue;streamReader >> dValue;QByteArray byValue;streamReader >> byValue;QString qstr = QString::fromLocal8Bit(byValue);strValue = string((const char *)qstr.toLocal8Bit());for (int i = 0; i < iValue; i++){int iTemp;streamReader >> iTemp;vStrSize.push_back(iTemp);}for (int j = 0; j < iValue; j++){QByteArray qstrValue;streamReader >> qstrValue;QString str = QString::fromLocal8Bit(qstrValue);string strValue = string((const char *)str.toLocal8Bit());vStr.push_back(strValue);}}
};

在代码中write就是把结构体转为二进制,read就是把二进制转为结构体,使用方法

MsgBody body;
// 对 body 的各个变量赋值
QByteArray packet;
body.write(&packet);body.read(packet);  // packet为二进制

这种方法就是在使用QT写tcp的时候好用
注:
QT如果是string类型中包含有中文的话,需要转编码格式,上述的编码格式转换适用于windows

第二种 强转
强转的方法适用于结构体中没有可变长度的变量,可变长度就是结构体中包含string, vector类型

struct NET_HEAD
{
public:int recvId;   // 接收消息方	int sendId;  // 发送消息方	int msgType;     // 消息类型int dataLen;     // 数据长度  
};int main()
{char *m_Msg_buf = new char[40960];;//消息缓冲区char *m_Recv_buf= new char[4096];;//消息缓冲区NET_HEAD head;// 结构体转为二进制memcpy((void *)m_Msg_buf, (void *)&head, sizeof(NET_HEAD ));// s_server 是tcp连接int recv_len = recv(s_server, m_Recv_buf, 4096, 0);memcpy(m_Msg_buf, m_Recv_buf, recv_len);// 二进制强转为结构体	NET_HEAD* header = (NET_HEAD*)m_Msg_buf;
}

如果使用QT的话更简单了

// 还是上面的结构体,在main函数中写以下代码
NET_HEAD head;
// 为 head 赋值
QByteArray packet;
packet.append((char*)&head, sizeof(NET_HEAD));  // 将 结构体强转为二进制// 二进制转为结构体
// packet 是接受到的二进制
NET_HEAD * head1 = (NET_HEAD *)packet.data();  

第三种 纯c++
用纯C++来进行序列化和反序列化可变结构体比较有意思,其实也就是memcpy,参考这个

struct ComplexData {int id;int len;string name;int iStrVecLen;vector<int> viStr;vector<string> vStr;int valuesLen;vector<double> values;char* serialize() const {int offset = 0;char* buffer = new char[sizeof(ComplexData)];memcpy(buffer + offset, &this->id, sizeof(int));offset += sizeof(int);memcpy(buffer + offset, &this->len, sizeof(int));offset += sizeof(int);memcpy(buffer + offset, (this->name).data(), this->len);offset += this->len;offset += 1;   // 加1 是为了防止string类型后面有 \0 memcpy(buffer + offset, &this->iStrVecLen, sizeof(int));offset += sizeof(int);for (int i = 0; i < this->iStrVecLen; i++){int iValue = this->viStr[i];memcpy(buffer + offset, &iValue, sizeof(int));offset += sizeof(int);}for (int i = 0; i < this->iStrVecLen; i++){string str = this->vStr[i];int sizeStr = this->viStr[i];memcpy(buffer + offset, str.data(), sizeStr);offset += sizeStr;offset += 1;}memcpy(buffer + offset, &this->valuesLen, sizeof(int));offset += sizeof(int);for (int i = 0; i < this->valuesLen; i++){memcpy(buffer + offset, &(this->values[i]), sizeof(double));offset += sizeof(double);}return buffer;}// 反序列化函数void deserialize(char* buffer) {int offset = 0;memcpy(&this->id, buffer + offset, sizeof(int));offset += sizeof(int);memcpy(&this->len, buffer + offset, sizeof(int));offset += sizeof(int);this->name = std::string(buffer + offset, this->len);offset += this->len;offset += 1;memcpy(&this->iStrVecLen, buffer + offset, sizeof(int));offset += sizeof(int);for (int i = 0; i < this->iStrVecLen; i++){int iValue;memcpy(&iValue, buffer + offset, sizeof(int));offset += sizeof(int);this->viStr.push_back(iValue);}for (int i = 0; i < this->iStrVecLen; i++){int iValue = this->viStr[i];string str = std::string(buffer + offset, iValue);offset += iValue;offset += 1;this->vStr.push_back(str);}memcpy(&this->valuesLen, buffer + offset, sizeof(int));offset += sizeof(int);for (int i = 0; i < this->valuesLen; i++){double dValue;memcpy(&dValue, buffer + offset, sizeof(double));offset += sizeof(double);this->values.push_back(dValue);}}
};int main()
{string name = "Join Doe";vector<double> vec;vec.push_back(1.1);vec.push_back(2.2);vec.push_back(3.3);string str1 = "teards sfdf";string str2 = "sdsHJJMHj";string str3 = "测试代码";string str4 = "123qweer长度";vector<string> vecStr;vecStr.push_back(str1);vecStr.push_back(str2);vecStr.push_back(str3);vecStr.push_back(str4);vector<int> vecIStr;vecIStr.push_back(str1.size());vecIStr.push_back(str2.size());vecIStr.push_back(str3.size());vecIStr.push_back(str4.size());ComplexData oriData;oriData.id = 1;oriData.len = name.size();oriData.name = name;oriData.iStrVecLen = vecStr.size();oriData.viStr = vecIStr;oriData.vStr = vecStr;oriData.valuesLen = vec.size();oriData.values = vec;// 序列化并发送char* buffer = oriData.serialize();// 接收并反序列化ComplexData receivedObj;receivedObj.deserialize(buffer);cout << "recvData.id: " << receivedObj.id << endl;cout << " recvData.name: " << receivedObj.name << endl;for (int i = 0; i < receivedObj.values.size(); i++){cout << receivedObj.values[i] << endl;}for (int i = 0; i < receivedObj.vStr.size(); i++){cout << receivedObj.vStr[i] << endl;}return 0;
}

纯C++序列化和反序列化对于string类型中有中文的也不用担心编码格式了

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com