如何通过套接字发送结构
C++ How to send structures over socket?
假设我有一个结构:
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不直接包含数据。他们指着它。这意味着,当您将包含向量的结构转储到套接字中时,您将转储指向内存的指针,而不是指向的内容。这将导致(充其量)接收端崩溃。
它将对单个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协议缓冲区或其他人已经链接到的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对于这样的任务,这可能是最健壮、通用、可靠、易于使用甚至是跨平台的方法。
- WTSEnumerateProcesses与套接字和数据结构
- 在 UDP 套接字上发送结构、浮点数和 int C++
- 使用 UDP 协议从 Windows 套接字发送到 Qt 套接字的网络数据包上的结构编码和解码
- 通过 TCP 套接字发送结构 C++
- C++:无法使套接字、螺纹和结构工作
- C/C++ 中的套接字编程 - 接收由 typedef 结构定义的消息
- 套接字编程:结构 sockaddr VS 结构sockaddr_in
- 如何使用套接字构建健壮的网络体系结构
- C++套接字服务器体系结构
- 如何序列化一个8位整数的结构用于套接字编程
- 通过std::asio-tcp套接字发送结构
- 从 Linux 中的管道/套接字读取所有结构或什么都没有
- C++ 套接字:结构地址的大小
- 分段错误通过 TCP 套接字发送结构
- 通过套接字发送结构并接收中文字母
- 将数据从两种不同的数据结构插入 std::map <std::string, int> mymap 并通过套接字发送
- 我通过函数SENDTO通过套接字(c++)发送结构,并通过RECVFORM接收,但总是得到一些垃圾值
- 从LISP的套接字中读取c++结构
- 如何通过套接字发送结构
- 如何通过套接字发送与c++兼容的Java结构体