如何通过网络套接字可移植地发送C结构?

时间:2015-02-11 13:07:03

标签: c portability

假设我有一个如下定义的C结构:

typedef struct servData {
    char max_word[MAX_WORD];
    char min_word[MAX_WORD];
    int word_count ;
} servSendData ;

其中' MAX_WORD'可以是任何价值。 现在,如果我有这个结构的实例:

servSendData  myData ;

如果我填充此实例然后通过网络发送,考虑到我希望我的服务器以及客户端在64位系统或32位上运行,是否会出现任何可移植性问题系统

我将发送和接收数据如下:

//server side
strcpy(myData.max_word, "some large word") ;
strcpy(myData.min_word, "small") ;
myData.word_count=100 ;
send(sockFd, (char*)&myData, sizeof(myData);

//client side
recv(sockFd, (char*)&myData, sizeof(myData);
printf("large word is %s\n", myData.max_word) ;
printf("small word is %s\n", myData.min_word) ;
printf("total words is %d\n", myData.word_count) ;

5 个答案:

答案 0 :(得分:5)

是的,肯定成为可移植性问题。

即使在同一平台上的不同编译器之间,结构成员的对齐也可能不同,更不用说不同的平台了。并且所有这些都假设sizeof(int)在所有这些中都是相同的(虽然被授予,但通常是 - 但是你真的想依靠"通常"并希望最好?)。

即使MAX_WORD在两台计算机上都相同,也是如此(我假设他们是从这里出来的;如果他们不是,那么你在这里遇到麻烦)

您需要做的是分别发送(和接收)每个字段。 sizeof(int)和endianness也存在问题,因此我添加了对htonl()的调用以从系统转换为网络字节顺序(反函数为ntohl())。它们都返回uint32_t,它具有固定的,已知的大小。

send(sockFd, myData.max_word, sizeof(myData.max_word)); // or just MAX_WORD
send(sockFd, myData.min_word, sizeof(myData.min_word));
uint32_t count = htonl(myData.word_count); // convert to network byte order
send(sockFd, &count, sizeof(count));

// error handling!
if((ret = recv(sockFd, myData.max_word, sizeof(myData.max_word))) != sizeof(myData.max_word))
{
    // handle error or read more data
}
... // and so on
// remember to convert back from network byte order on recv!
// also keep in mind the third field is now `uint32_t`, and not `int` in the stream

答案 1 :(得分:1)

你必须要关心端序。

你应该使用hton()或ntoh()函数来转换小端和大端。

答案 2 :(得分:1)

正如其他人所说,在不同编译器/字大小/端序结构的不同机器之间复制C结构存在实际问题。解决此问题的一种常见方法是将数据转换为与机器无关的格式,通过网络传输,然后将其转换回接收器上的结构。这是一个常见的要求,已经存在多种技术来实现这一点 - 我最初想到的两个技术是gsoaprpcgen,尽管可能还有很多其他选择。

我主要使用gsoap,在你超越初始学习曲线后,你可以开发出可扩展的强大解决方案(有多个线程),并为你处理网络和数据翻译。

如果您不想沿着这条路走下去,那么最安全的方法是编写将数据转换为标准字符串格式的例程(如果您遇到Unicode问题,那么需要考虑到这一点)然后通过网络发送。

答案 3 :(得分:0)

您可以使用structure packing。对于大多数C编译器,您可以强制执行特定的结构对齐。它有时用于您需要的内容 - 通过网络传输struct

请注意,这仍会留下字节序问题,因此这不是一种通用解决方案。

答案 4 :(得分:0)

如果您不是在编写嵌入式软件,那么在没有正确序列化的情况下在应用程序之间发送数据通常不是一个好主意。

使用原始套接字也是如此,这不是很方便,感觉有点像“重新发明轮子”。

许多图书馆可以为您提供帮助!当然,您不必使用它们,但阅读文档并了解它们的工作方式将有助于您做出更好的选择。您尚未计划的事情可以开箱即用(例如,当您想要更新系统时会发生什么,以及消息格式是否会发生变化?)

对于序列化,请阅读这些通用格式:

  • 人类可读:JSON,XML,YAML,其他......
  • 二进制:ProtobufTPLAvro,BSON,MessagePack等等

对于套接字抽象,请查找

  • 提升ASIO
  • ZeroMQ
  • nanomsg
  • 许多其他人