14

Say I have a structure:

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

For example, I want to send/recv the whole company using socket (UDP). So, send and recv once.

How can I do that? Could you please give me some code sinppet? How to send everything and read everything.

Thanks!

9
  • 8
    Serialize it. Send it. Deserialize it. Up to you how you encode the data during serialization. Examples: Google's protocol buffers and JSON. Commented Dec 14, 2011 at 23:29
  • 2
    There are so many different ways to achieve serialization of arbitrary structures in C/C++. Do some reading, decide which method suits your project best, and go for it. You can even roll your own. Commented Dec 14, 2011 at 23:33
  • 1
    You have to define a serialization format. Serialize all the data. Send it. On the other receive it then de-serialize it into your data structure. How you serialize it will depend on other factors (like how big it is and how easy to debug you want it to be). Personally I would use read/write and let the underlying socket worry about buffering (trying to do the buffering yourself is usually a waste of time as the underlying socket has been designed to use a buffer). Commented Dec 14, 2011 at 23:34
  • Which part are you having trouble with? The serialization part, or the "send" and "recv" part? Commented Dec 14, 2011 at 23:54
  • When doing serialization, avoid doing memcpy of struct pointers to network buffers. Also, when doing memcpy serialization, be explicit about copy sizes. Compiler differences between different computers may influence the padding of structs and the value of sizeof(size_t) and such. Or just use XML and call it a day. Commented Dec 14, 2011 at 23:56

5 Answers 5

22

The phrasing of your question suggests that what you're looking for is this:

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

This will basically dump all the memory of the company struct into your socket. This WILL NOT WORK in this instance. And even when it sort of works, it's a really bad idea. The reason it won't work is that vectors do not contain the data directly. They point at it. This means that when you dump the structure containing vectors into the socket, you will be dumping pointers to memory, but not the stuff being pointed at. This will result in (at best) crashes on the receiving side.

It would sort of work for individual person or car objects. These contain no pointers, and so their memory contains all the relevant values'

On the sending side:

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

On the receiving side:

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

But, this is still a bad idea. It relies on the sending side and receiving side having the exact same memory layout for their structures. This may not be true for any number of reasons. Some include one being on a PowerPC chip, and the other being on an Intel x86 chip. Or one being on a Windows machine compiled with Visual Studio and the other being on a Linux machine compiled with gcc. Or maybe someone has tweaked some compiler flags that cause the default structure layout to be different. Any number of reasons.

Really, you ought to use a serialization framework like everybody here has suggested. I would suggest Google protocol buffers or the Boost serialization framework that other people have already linked to. But there are many others.

Another serialization framework that should be mentioned because it is blazingly fast (almost as fast as straight dumping the memory image of a struct into a socket) is Cap'n Proto.

Sign up to request clarification or add additional context in comments.

Comments

9

Take a look at Google protocol buffers http://code.google.com/apis/protocolbuffers/ as a lite alternative to Boost serialization.

Comments

9

As others have already said, using some kind of serialization library will provide the most robust (and probably simplest to maintain) solution. If, though, you are really wanting to implement it all yourself, then the following shows the "idea" of how maybe to approach it. The following allocates a buffer, and then fills it up with the employees vector contents. The variable c is assumed to be of type company.

Some things to note:

  • The example uses a buffer to load up multiple entries for a single send. With UDP, it would typically not be desirable to send one entry at a time since it would result in one packet per entry.
  • The first value stored in the buffer is the number of items. In reality, some additional information would likely be needed (e.g., type of data). Otherwise the receiver would not necessarily know what it was getting.
  • The char data is copied in and null terminated. Another way would be to prefix that data with the length and forego the null terminator.
  • It might be wise to store integer values in the buffer aligned on 4 byte boundaries (depends on the system).
  • htonl is used to store the integer values in network byte order. The receiving end should use ntohl to read them out.

Simple and very incomplete example:

 // 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. 

Comments

8

If you are to make many of these, you may want to look in Thrift. It will automatically generate all the necessary code to serialize all the structures for you so you don't have to do it manually.

They support strings too so very practical.

Oh! And it's free. 8-)

http://thrift.apache.org/

Another thing, it sends binary data as such, so you won't have to convert numbers to strings and vice versa. That's a lot faster to do so if most of your data are not strings.

Comments

6

Use Boost serialization library:

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

This is probably the most robust, universal, reliable, easy to use and even cross-platform way for such task.

1 Comment

Note that some versions of the boost serialization library were NOT working correctly (1.37 to 1.42 or something like that?). Also in regard to robustness, I find this library complicated to use.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.