在网络通讯过程中往往涉及一些有关联的参数传递,例如结构体之类的。对于结构体其实方法挺简单,由于结构体对象在内存中分配的空间都是连续的,所以可以将整个结构体直接转化成字符串发送,到了接收方再将这个字符串还原成结构体就可以了。
网络传输struct数据的约束有两个:
约束一、就是结构体的大小必须是固定的,不能含有可变大小数据,例如CString、string之类的数据。换句话说,结构体所包含的数据必须是C++基本类型数据以及这些基本类型数据所形成固定大小的数组。
约束二、就是传接两方结构体定义必须一模一样,包括数据声明次序。如果要发送的结构体包含“#pragma pack (n)”,则接收方在定义此结构体时也要使用“#pragma pack (n)”声明。传接之所以能够成功是因为结构体数据的内存区域连续性所保证的
本来嘛在C/C++中所有数据究其本质都是字节类型,只是在表现时各自不同罢了,所以只要能找到合适的转换为字节类型数据的途径就OK了。而字节类型和char类型一样都是一个字节长度,所以问题又等同于找一条合适途径,将信息转换为固定长度char数组类型。
1、结构体数据全部都是数组
- typedef struct _tag_user_info_
- {
- char cUserID[20];
- char cUserSex[10];
- char cUserName[18];
- char cUserNativePlace[50];
- } UserData;
- //发送方:创建一个对象并初始化各个参数,然后发送。
- UserData sendUser;
- memcpy ( sendUser.cUserID, "412902198312120311",sizeof("412902198312120311"));
- memcpy ( sendUser.cUserSex, "male",sizeof("male"));
- memcpy ( sendUser.cUserName, "JianYa.Lee",sizeof("JianYa.Lee"));
- memcpy (
- sendUser.cUserNativePlace,
- "Asia. P.R.C .HeNan-DengZhouShi",
- sizeof("Asia. P.R.C.HeNan-DengZhouShi")
- );
- send ( m_oSendSocket, (char*)&sendUser,sizeof(UserData), 0 );
需要注意的地方:send函数的第三个参数,也就是发送数据长度必需是结构体的大小,这样发送方就已经将这个sendUser对象以字符串的形式发送出去了,剩下的工作就由接收方来完成了
接收方:首先也必须有UserData这个结构体类型定义。其次,首先定义一个充分大char类型数组,用于接收网络发送数据。然后将接收到的数据用memcpy函数完成强转即可。
- // 定义的char数组足够大
- charcRcvBuffer[1024] = {0};
- // 定义一个UserData对象, 用于容纳转换信息
- UserData recvUser;
- recv( m_RcvSocket, cRcvBuffer, sizeof(cRcvBuffer),0 );
- // 强转, 请注意sizeof的内容
- memcpy( &recvUser, cRcvBuffer, sizeof(UserData) );
这样得到的recvUser对象里的数据与sendUser相同了。
2、结构体数据没有包含数组
- // 发送方:创建struct结构体
- typedef struct _tag_other_data_
- {
- INT32 nValue;
- char cValue;
- bool blValue;
- float fValue;
- double dValue;
- short sValue;
- } SecondData;
- // 定义结构体对象,并初始化
- SecondData oScdData;
- // 初始化数据内容
- oScdData.blValue = true;
- oScdData.cValue = 'h';
- oScdData.dValue = 0.1234567;
- oScdData.fValue =3.14159f;
- oScdData.nValue = 123456;
- oScdData.sValue = 0x1024;
- // 注意sizeof内容
- send(m_oSendSocket, (char*)&oScdData,sizeof(SecondData), 0);
- 接收方:首先定义SecondData结构体,数据类型、声明次序需完全一样;其次声明一个足够大的char类型数组;最后强转。
- // 定义char类型数组
- charcRcvBuffer[1024] = {0};
- SecondData oRcvData;
- // 注意sizeof内容
- recv(m_oRcvSocket, cRcvBuffer, sizeof(cRcvBuffer), 0);
- // 强制转换, 注意sizeof内容
- memcpy(&oRcvData, cRcvBuffer, sizeof(SecondData));
接收方:首先定义SecondData结构体,数据类型、声明次序需完全一样;其次声明一个足够大的char类型数组;最后强转。
- // 定义char类型数组
- charcRcvBuffer[1024] = {0};
- SecondData oRcvData;
- // 注意sizeof内容
- recv(m_oRcvSocket, cRcvBuffer, sizeof(cRcvBuffer), 0);
- // 强制转换, 注意sizeof内容
- memcpy(&oRcvData, cRcvBuffer, sizeof(SecondData));
3、多个结构体数据的传接
发送方:
- struct structA
- {
- INT32 nValue;
- char cValue;
- };
- struct structB
- {
- bool blValue;
- short sValue;
- };
- struct structC
- {
- float fValue;
- char cValue;
- unsigned long unValue;
- };
- // 三个结构体定义各不相同,现在要给它们建立一个统一的传接模式,此时可以考虑使用联合union,外加一个类型指示。
- typedef struct _tag_unification_data_
- {
- // 用于指示结构体类型, 比如IS_STRUCT_A就代表structA、
- // IS_STRUCT_B就代表struct_B、
- // IS_STRUCT_C就代表structC
- INT32 nStructType;
- // 每次传送的是三种struct中的一种
- union
- {
- struct structA aData;
- struct structB bData;
- struct structC cData;
- };
- } PACKETDATA;
- // 结构体类型标识
- enum{IS_STRUCT_A, IS_STRUCT_B, IS_STRUCT_C};
- // 定义结构体对象,并初始化
- PACKETDATA oMyData;
- // 发送structA类型数据
- oMyData.nStructType = IS_STRUCT_A;
- oMyData.aData.cValue = 'g';
- oMyData.aData.nValue = 130;
- // 注意后面的sizeof内容
- send(oSendSocket, (char*)&oMyData,sizeof(PACKETDATA), 0);
接收方:
首先必需由PACKETDATA一样的定义;
其次,定义一个足够大的char数组;
最后完成强转,在使用的时候进行具体类型判断即可。
- // 定义char类型数组
- charcRcvBuffer[1024] = {0};
- PACKETDATA oRcvData;
- // 注意sizeof内容
- recv(m_oRcvSocket, cRcvBuffer, sizeof(cRcvBuffer), 0);
- // 强制转换, 注意sizeof内容
- memcpy(&oRcvData, cRcvBuffer, sizeof(PACKETDATA));
- // 在使用时进行具体类型判断
- switch (oRcvData.nStructType)
- {
- caseIS_STRUCT_A:
- // structA类型数据
- break;
- caseIS_STRUCT_B:
- // structB类型数据
- break;
- caseIS_STRUCT_C:
- // structC类型数据
- break;
- }