如何通过套接字发送结构

C++ How to send structures over socket?

本文关键字:结构 套接字 何通过      更新时间:2023-10-16

假设我有一个结构:

struct person
{
    char name[10];
    int age;
};
struct car
{
    int locationX;
    int locationY;
};
struct company
{
    vector<person> employees;
    vector<car> cars;
};

例如,我想使用套接字(UDP)来send/recv整个company。所以,发送和接收一次。

我该怎么做呢?你能给我一些代码吗?如何发送和阅读所有内容。

谢谢!

你的问题的措辞表明你正在寻找的是:

company foo;
send(sockfd, &foo, sizeof(foo), 0); // DO NOT do this

这基本上会将company结构体的所有内存转储到套接字中。这个在这个实例中将不起作用。即使它有点作用,这也是一个非常糟糕的主意。它不起作用的原因是vector s不直接包含数据。他们指着它。这意味着,当您将包含向量的结构转储到套接字中时,您将转储指向内存的指针,而不是指向的内容。这将导致(充其量)接收端崩溃。

它将对单个personcar对象起作用。它们不包含指针,因此它们的内存包含所有相关值'

发送端:

person joe = { "Joe", 35 };
send(sockfd, &joe, sizeof(joe), 0); // may work, but is a bad idea, see below

接收端:

person joe;
recv(sockfd, &joe, sizeof(joe), 0);

但是,这仍然是一个坏主意。它依赖于发送端和接收端对其结构具有完全相同的内存布局。由于种种原因,这可能是不正确的。其中包括一个在PowerPC芯片上,另一个在Intel x86芯片上。或者一个在用Visual Studio编译的Windows机器上,另一个在用gcc编译的Linux机器上。或者可能有人调整了一些编译器标志,导致默认结构布局不同。有很多原因

真的,您应该像这里每个人建议的那样使用序列化框架。我建议使用Google协议缓冲区或其他人已经链接到的Boost序列化框架。但是还有很多其他的。

另一个应该提到的序列化框架是Cap'n Proto,因为它非常快(几乎和直接将结构体的内存映像转储到套接字中一样快)。

看看Google协议缓冲区http://code.google.com/apis/protocolbuffers/

正如其他人已经说过的,使用某种序列化库将提供最健壮的(可能也是最容易维护的)解决方案。但是,如果你真的想要自己实现它,那么下面的内容将展示如何实现它的"想法"。下面分配一个缓冲区,然后用雇员向量内容填充它。假定变量c的类型为company

注意事项:

  • 示例使用缓冲区为单个发送加载多个条目。对于UDP,通常不希望一次发送一个条目,因为它会导致每个条目一个数据包。
  • 存储在缓冲区中的第一个值是项数。实际上,可能需要一些额外的信息(例如,数据类型)。否则接收者不一定知道它收到了什么。
  • 字符数据被拷贝进来,并以空结束。另一种方法是用长度作为数据的前缀,并放弃空终止符。
  • 将整数值存储在以4字节边界对齐的缓冲区中可能是明智的(取决于系统)。
  • htonl用于按网络字节顺序存储整数值。接收端应使用ntohl读出。

简单而非常不完整的例子:

   // allocate buffer to store all the data for a send.  In a real world
   // this would need to be broken up into appropriately sized chunks
   // to avoid difficulties with UDP packet fragmentation.
   // This likely over-allocates because the structure likely has padding
   char *buf = new char[ sizeof( uint32_t ) +   // for total number of entries
                  sizeof( person ) * c.employees.size() ];  // for each entry
   char *pos = buf;
   // Indicate how many are being sent
   *(uint32_t*)pos = htonl( c.employees.size() );
   pos += sizeof uint32_t;
   for ( vector<person>::iterator pi = c.employees.begin();
         pi != c.employees.end(); pi++ )
      {
      *(uint32_t*)pos = htonl( pi->age );
      pos += sizeof uint32_t;
      strcpy( pos, pi->name );
      pos += strlen( pi->name ) + 1;
      }
   send( 0, buf, (int)( pos - buf ), 0 );

   delete [] buf;
   // The receiving end would then read the number of items and 
   // reconstruct the structure.

如果你想做很多这样的事情,你可能想看看节俭。它会自动生成所有必要的代码来序列化所有的结构,所以你不必手动做。

它们也支持字符串,所以非常实用。

哦!而且是免费的。8 -)

http://thrift.apache.org/

另一件事,它发送二进制数据,所以你不需要将数字转换为字符串,反之亦然。如果大多数数据不是字符串,这样做会快很多

使用Boost序列化库:

http://www.boost.org/doc/libs/1_48_0/libs/serialization/doc/index.html

对于这样的任务,这可能是最健壮、通用、可靠、易于使用甚至是跨平台的方法。