通过TCP发送结构(C编程)

时间:2009-11-14 16:56:28

标签: c macos tcp struct send

我有一个客户端和服务器程序,我想从客户端发送整个结构,然后在服务器上输出结构成员“ID”。

我已完成所有连接等,并已设法通过以下方式发送字符串:

send(socket, string, string_size, 0);

那么,是否可以通过send()发送结构而不是字符串?我可以将服务器上的缓冲区替换为相同类型的空结构吗?

7 个答案:

答案 0 :(得分:4)

客户端和服务器机器“是否相同”?你提出的建议只有在每一端的C编译器在内存中的结构完全相同时才有效。有很多原因可能不是这种情况。例如,客户端和服务器宏可能具有不同的体系结构,那么它们在内存中表示数字的方式(big-endian,little-endian)可能会有所不同。即使客户机器和服务器机器具有相同的体系结构,两个不同的C编译器可能对它们如何在存储器中布置结构具有不同的策略(例如,字段之间的填充以在字边界上对齐整数)。即使是具有不同标志的相同的 conmpiler也可能会产生不同的结果。

实际上,我猜你的客户端和服务器是同一种机器,所以你提出的是可行的,但是你需要注意,作为一般规则,它不会,这就是为什么标准,如发明了CORBA,或者为什么人们使用一些通用的表示,比如XML。

答案 1 :(得分:2)

如果客户端和服务器以完全相同的方式布局结构,则可以使用相同的填充来表示字段大小相同。例如,如果你的结构中有long,那么一台机器上可能是32位,另一台机器上可能是64位,在这种情况下,结构将无法正确接收。

在您的情况下,如果客户端和服务器总是在非常相似的C实现上(例如,如果这只是您用于学习一些基本概念的代码,或者由于某些其他原因您知道您的代码只需要在你当前版本的OSX上运行),那么你可以侥幸逃脱它。请记住,您的代码不一定能在其他平台上正常运行,并且在适用于大多数实际情况之前还有更多工作要做。

对于大多数客户端 - 服务器应用程序,这意味着答案是您不能一般地执行此操作。您实际做的是根据发送的字节数,顺序,含义等来定义消息。然后在每一端,您执行特定于平台的操作,以确保您使用的结构具有完全所需的布局。即便如此,如果您要发送struct little-endian的整数成员,那么您可能必须进行一些字节交换,然后您希望您的代码在big-endian机器上运行。存在数据交换格式,如XML,json和Google的协议缓冲区,因此您无需执行此类繁琐工作。

[编辑:还记得当然有些结构成员永远无法通过网络发送。例如,如果你的结构中有一个指针,那么地址指的是发送机器上的内存,并且在接收端没用。抱歉,如果这对你来说已经很明显了,但当他们刚刚开始使用C时,对于每个人来说当然不是很明显。

答案 2 :(得分:1)

如果你正确地做这件事,那么通过网络发送结构很难。

Carl是对的 - 你可以通过网络发送一个结构:

send(socket, (char*)my_struct, sizeof(my_struct), 0);

但事情就是这样:

  • sizeof(my_struct)可能会在客户端和服务器之间发生变化。编译器通常会进行一些填充和对齐,因此除非您明确定义对齐(可能使用#pragma pack()),否则该大小可能会有所不同。
  • 另一个问题往往是字节顺序。有些机器是big-endian,有些是little-endian,所以字节的排列可能不同。实际上,除非您的服务器或客户端在非英特尔硬件上运行(可能不是这种情况),否则这个问题在理论上比在实践中更多。

因此,人们经常提出的解决方案是使用一个序列化结构的例程。也就是说,它一次向结构发送一个数据成员,确保客户端和服务器只发送()和recv()您编入程序的确切指定字节数。

答案 3 :(得分:1)

你可以,但你需要了解两件重要的事情。

  1. 两端的节目必须ABI兼容。它们通常是两端运行在相同的处理器体系结构,相同的OS上,使用相同的编译器和编译器标志进行编译。
  2. TCP是一个流。您必须确保发送整个结构。查看send()调用的文档 - 它返回发送的nr个字节 - 这可能比你告诉它的要少。接收方也一样。仅仅因为您发送了带有1个发送呼叫的结构,并不意味着您将通过1次recv呼叫接收它。这需要几次recv调用以获得所有部分。

答案 4 :(得分:0)

是的,相同类型的结构都具有相同的大小。如果你的指针投射正确,你就可以去了。

答案 5 :(得分:0)

一般来说,这样做是个坏主意,即使你的客户端和你的服务器都以同样的方式在内存中布局结构。

即使您不打算来回传递更复杂的数据结构(包括指针),我建议您在通过网络发送数据之前对其进行序列化。

答案 6 :(得分:-3)

将数据作为文本文件发送,然后在收到后对其进行解码。如果您希望将数据作为发送数据,这是最好的方式!