在C中通过TCP套接字传递结构

时间:2011-05-11 10:00:25

标签: c sockets

我正在用C编写一个小型客户端服务器应用程序。

在客户端方面,我有一个像

这样的结构
#pragma pack(1)   // this helps to avoid serialization while sending over network. 
typedef struct _viewBoxClient_Info
{
  unsigned long viewBoxID;
  int bRT_flag;
  int nFrameNum;
  char frameData[1000];   
}viewBoxClient_info_send ;
#pragma pack(0)   // turn packing off 

并将变量填充为

struct _viewBoxClient_Info client_info;
client_info.bRT_flag= 10;/*0 for false, 1 for true*/
client_info.viewBoxID=10000;
memcpy(client_info.frameData,buf,sizeof(client_info.frameData)); //char buf[] data is "is 1st line"
client_info.nFrameNum=1;

并使用以下函数发送到服务器

send(sock, (char *)&client_info, bytesRead, 0);

在服务器端,我有一个结构(与客户端结构相同),

#pragma pack(1)   // this helps to avoid serialization while sending over network.
typedef struct _lclviewBoxClient_Info
{
 unsigned long viewBoxID;
 int bRT_flag;
 int nFrameNum;
 char frameData[1000];
}viewBoxClient_info_receive ;
#pragma pack(0)   // turn packing off

并接收消息并在屏幕上打印,

viewBoxClient_info_receive lcl_viewBox;
ssize_t bytesReceived = recv( *nfd, &lcl_viewBox, sizeof(struct _lclviewBoxClient_Info), 0);
printf("\nlcl_viewBox.bRT_flag:%d\n",lcl_viewBox.bRT_flag);
printf("lcl_viewBox.nFrameNum:%d\n",lcl_viewBox.nFrameNum);
printf("lcl_viewBox.frameData:%s\n",lcl_viewBox.frameData);

服务器屏幕上的O / p,

 lcl_viewBox.bRT_flag:1
 lcl_viewBox.nFrameNum:1936287860
 lcl_viewBox.frameData: is 1st line

我不知道它在我的服务器端究竟发生了什么。我从客户端发送10个bRT_flag,在服务器上接收1个。还从客户端发送nFrameNum = 1并在服务器上以nFrameNum:1936287860接收。 frameData也在客户端我发送“这是第一行”,在服务器接收“只是第一行”。 有人会帮助摆脱这个问题吗?

感谢和问候,

3 个答案:

答案 0 :(得分:2)

不应该这样:

send(sock, (char *)&client_info, bytesRead, 0);

是:

send(sock, (char *)&client_info, sizeof( client_info ), 0);

你应该检查send()的返回值,特别是recv()的返回值 - 不能保证调用recv会一次性获取你的结构。

答案 1 :(得分:2)

发送这样的原始结构是一个非常糟糕的主意。

你必须处理字节顺序(字节顺序),打包(即使使用#pragma pack仍然可能存在问题),而另一个问题是像'int'这样的类型的大小可能因平台而异。

我建议使用像Google Protocol Buffers这样的序列化库来帮助您。如果您仍想自己动手,则需要查找htonl等函数,将整数类型转换为网络字节顺序,并开始使用uint32_t等固定大小的原语。

您还应该立即停止发送整个结构,而是编写helCl函数,如writeClientStruct(int sock,struct client_struct *),它将分别发送每个成员值,以避免平台之间的打包问题。

答案 2 :(得分:0)

一种解释是您的客户端和服务器对“unsigned long”的大小有不同的解释。 (在不同的机器或不同的编译器选项上运行,其他是32位和其他64位)。

这可以解释症状:

  • bRT_flag将32位移位到nFrameNum
  • nFrameNum包含来自frameData的前32位(1936287860 - > 0x73696874 - >“siht” - > with endian swap“this”)

对此进行简单检查将检查sizeof(结构)或sizeof(unsigned long)以查看它们是否匹配。

请参阅Mike Weller的帖子,了解如何正确解决此问题。