TCP编程之一 传输struct类型数据条件

在网络通讯过程中往往涉及一些有关联的参数传递,例如结构体之类的。对于结构体其实方法挺简单,由于结构体对象在内存中分配的空间都是连续的,所以可以将整个结构体直接转化成字符串发送,到了接收方再将这个字符串还原成结构体就可以了。

网络传输struct数据的约束有两个:

约束一、就是结构体的大小必须是固定的,不能含有可变大小数据,例如CString、string之类的数据。换句话说,结构体所包含的数据必须是C++基本类型数据以及这些基本类型数据所形成固定大小的数组。

约束二、就是传接两方结构体定义必须一模一样,包括数据声明次序。如果要发送的结构体包含“#pragma pack (n)”,则接收方在定义此结构体时也要使用“#pragma pack (n)”声明。传接之所以能够成功是因为结构体数据的内存区域连续性所保证的

本来嘛在C/C++中所有数据究其本质都是字节类型,只是在表现时各自不同罢了,所以只要能找到合适的转换为字节类型数据的途径就OK了。而字节类型和char类型一样都是一个字节长度,所以问题又等同于找一条合适途径,将信息转换为固定长度char数组类型。

1、结构体数据全部都是数组

[cpp]  view plain  copy
  1. typedef  struct _tag_user_info_  
  2. {  
  3.     char cUserID[20];  
  4.     char cUserSex[10];  
  5.     char cUserName[18];  
  6.     char cUserNativePlace[50];  
  7. } UserData;  
  8.    
  9.   //发送方:创建一个对象并初始化各个参数,然后发送。  
  10.    
  11. UserData sendUser;  
  12. memcpy ( sendUser.cUserID, "412902198312120311",sizeof("412902198312120311"));  
  13. memcpy ( sendUser.cUserSex, "male",sizeof("male"));  
  14. memcpy ( sendUser.cUserName, "JianYa.Lee",sizeof("JianYa.Lee"));  
  15.    
  16. memcpy (  
  17. sendUser.cUserNativePlace,  
  18. "Asia. P.R.C .HeNan-DengZhouShi",  
  19. sizeof("Asia. P.R.C.HeNan-DengZhouShi")  
  20. );  
  21.    
  22. send ( m_oSendSocket, (char*)&sendUser,sizeof(UserData), 0 );  

需要注意的地方:send函数的第三个参数,也就是发送数据长度必需是结构体的大小,这样发送方就已经将这个sendUser对象以字符串的形式发送出去了,剩下的工作就由接收方来完成了

 

  接收方:首先也必须有UserData这个结构体类型定义。其次,首先定义一个充分大char类型数组,用于接收网络发送数据。然后将接收到的数据用memcpy函数完成强转即可。

[cpp]  view plain  copy
  1. // 定义的char数组足够大  
  2. charcRcvBuffer[1024]  = {0};  
  3.    
  4. // 定义一个UserData对象, 用于容纳转换信息  
  5. UserData recvUser;  
  6. recv( m_RcvSocket, cRcvBuffer, sizeof(cRcvBuffer),0 );  
  7.    
  8. // 强转, 请注意sizeof的内容  
  9. memcpy( &recvUser, cRcvBuffer, sizeof(UserData) );  

这样得到的recvUser对象里的数据与sendUser相同了。

2、结构体数据没有包含数组

[cpp]  view plain  copy
  1. // 发送方:创建struct结构体  
  2. typedef struct _tag_other_data_  
  3. {  
  4.        INT32  nValue;  
  5.     char  cValue;  
  6.     bool  blValue;  
  7.     float  fValue;  
  8.     double  dValue;  
  9.     short  sValue;  
  10. } SecondData;  
  11.    
  12. // 定义结构体对象,并初始化  
  13. SecondData oScdData;  
  14.    
  15. // 初始化数据内容  
  16. oScdData.blValue = true;  
  17. oScdData.cValue = 'h';  
  18. oScdData.dValue = 0.1234567;  
  19. oScdData.fValue  =3.14159f;  
  20. oScdData.nValue = 123456;  
  21. oScdData.sValue = 0x1024;  
  22.    
  23. // 注意sizeof内容  
  24. send(m_oSendSocket, (char*)&oScdData,sizeof(SecondData), 0);  
  25.    
  26. 接收方:首先定义SecondData结构体,数据类型、声明次序需完全一样;其次声明一个足够大的char类型数组;最后强转。  
  27. // 定义char类型数组  
  28. charcRcvBuffer[1024] = {0};  
  29.    
  30. SecondData oRcvData;  
  31.    
  32. // 注意sizeof内容  
  33. recv(m_oRcvSocket, cRcvBuffer, sizeof(cRcvBuffer), 0);  
  34.    
  35. // 强制转换, 注意sizeof内容  
  36. memcpy(&oRcvData, cRcvBuffer, sizeof(SecondData));  


接收方:首先定义SecondData结构体,数据类型、声明次序需完全一样;其次声明一个足够大的char类型数组;最后强转。

[cpp]  view plain  copy
  1. // 定义char类型数组  
  2. charcRcvBuffer[1024] = {0};  
  3.    
  4. SecondData oRcvData;  
  5.    
  6. // 注意sizeof内容  
  7. recv(m_oRcvSocket, cRcvBuffer, sizeof(cRcvBuffer), 0);  
  8.    
  9. // 强制转换, 注意sizeof内容  
  10. memcpy(&oRcvData, cRcvBuffer, sizeof(SecondData));  

3、多个结构体数据的传接

发送方:

[cpp]  view plain  copy
  1. struct structA  
  2. {  
  3.     INT32 nValue;  
  4.     char    cValue;  
  5. };  
  6.    
  7. struct structB  
  8. {  
  9.     bool  blValue;  
  10.     short  sValue;  
  11. };  
  12.    
  13. struct structC  
  14. {  
  15.     float fValue;  
  16.     char  cValue;  
  17.     unsigned  long  unValue;  
  18. };  
  19.    //  三个结构体定义各不相同,现在要给它们建立一个统一的传接模式,此时可以考虑使用联合union,外加一个类型指示。  
  20. typedef  struct _tag_unification_data_  
  21. {  
  22. // 用于指示结构体类型, 比如IS_STRUCT_A就代表structA、  
  23. // IS_STRUCT_B就代表struct_B、  
  24.     // IS_STRUCT_C就代表structC  
  25.     INT32  nStructType;  
  26.      
  27.     // 每次传送的是三种struct中的一种  
  28.     union  
  29.     {  
  30.         struct structA aData;  
  31.         struct structB bData;  
  32.         struct structC cData;  
  33.     };  
  34. }  PACKETDATA;  
  35.    
  36. // 结构体类型标识  
  37.     enum{IS_STRUCT_A, IS_STRUCT_B, IS_STRUCT_C};  
  38.    
  39. // 定义结构体对象,并初始化  
  40.     PACKETDATA oMyData;  
  41.    
  42.     // 发送structA类型数据  
  43.     oMyData.nStructType  = IS_STRUCT_A;  
  44.     oMyData.aData.cValue = 'g';  
  45.     oMyData.aData.nValue = 130;  
  46.    
  47.     // 注意后面的sizeof内容  
  48. send(oSendSocket, (char*)&oMyData,sizeof(PACKETDATA), 0);  

接收方:

首先必需由PACKETDATA一样的定义;

其次,定义一个足够大的char数组;

最后完成强转,在使用的时候进行具体类型判断即可。

[cpp]  view plain  copy
  1. // 定义char类型数组  
  2. charcRcvBuffer[1024] = {0};  
  3.    
  4. PACKETDATA oRcvData;  
  5.    
  6. // 注意sizeof内容  
  7. recv(m_oRcvSocket, cRcvBuffer, sizeof(cRcvBuffer), 0);  
  8.    
  9. // 强制转换, 注意sizeof内容  
  10. memcpy(&oRcvData, cRcvBuffer, sizeof(PACKETDATA));  
  11.    
  12. // 在使用时进行具体类型判断  
  13. switch (oRcvData.nStructType)  
  14.    {  
  15. caseIS_STRUCT_A:  
  16.         // structA类型数据  
  17.         break;  
  18.    
  19. caseIS_STRUCT_B:  
  20.         // structB类型数据  
  21.         break;  
  22.    
  23. caseIS_STRUCT_C:  
  24.         // structC类型数据  
  25.         break;  
  26. }  

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值