说我有一个结构:
struct person
{
char name[10];
int age;
};
struct car
{
int locationX;
int locationY;
};
struct company
{
vector<person> employees;
vector<car> cars;
};
例如,我希望send/recv
使用套接字(UDP)company
。所以,发送和recv一次。
我该怎么做?你能给我一些代码吗?如何发送所有内容并阅读所有内容。
谢谢!
答案 0 :(得分:17)
你的问题的措词表明你正在寻找的是:
company foo;
send(sockfd, &foo, sizeof(foo), 0); // DO NOT do this
这基本上会将company
结构的所有内存转储到套接字中。在这种情况下,将无法工作。即使它有点工作,这也是一个非常糟糕的主意。它不起作用的原因是vector
不直接包含数据。他们指着它。这意味着当您将包含向量的结构转储到套接字中时,您将转储指向内存的指针,但不会转向指向的内容。这将导致接收方(最好)崩溃。
对于单个person
或car
对象,它会起作用。它们不包含指针,因此它们的内存包含所有相关值'
在发送方:
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 protocol buffers或其他人已经关联的Boost serialization framework。但还有很多其他人。
应该提到的另一个序列化框架,因为它非常快(几乎与直接将结构的内存映像转储到套接字中一样快)是Cap'n Proto。
答案 1 :(得分:8)
查看Google协议缓冲区http://code.google.com/apis/protocolbuffers/ 作为Boost序列化的精简替代品。
答案 2 :(得分:7)
如果要制作其中许多内容,您可能需要查看Thrift。它将自动生成所有必要的代码,以便为您序列化所有结构,因此您无需手动执行此操作。
他们支持字符串非常实用。
哦!它是免费的。 8 - )
另一方面,它会发送二进制数据,因此您不必将数字转换为字符串,反之亦然。如果您的大部分数据都不是字符串,那么这样做要快得多。
答案 3 :(得分:6)
使用Boost序列化库:
http://www.boost.org/doc/libs/1_48_0/libs/serialization/doc/index.html
这可能是最强大,通用,可靠,易于使用甚至跨平台的方式来完成此类任务。
答案 4 :(得分:5)
正如其他人已经说过的那样,使用某种序列化库将提供最强大(也可能是最简单的维护)解决方案。但是,如果您真的想要自己实现它,那么以下显示了如何处理它的“想法”。以下分配缓冲区,然后使用employees矢量内容填充它。假设变量c
属于company
类型。
有些注意事项:
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.