简体   繁体   中英

C++ How to send structures over socket?

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!

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 vector s 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 .

请查看Google协议缓冲区http://code.google.com/apis/protocolbuffers/,作为Boost序列化的精简替代方案。

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.

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.

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 (eg, 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM