How it works...

In this recipe, we created two binaries, sender and receiver, that emulate data exchange between two hosts. We can't make any assumptions regarding their endianness, which is why the data exchange format has to be unambiguous. 

The sender and receiver exchange data blocks of variable size. We encoded each block as a 4-byte integer in order to define the upcoming block size, followed by the block content.

While the sender does not generate any output on the screen, it saves an encoded block of data in a file. When we run the receiver, it is able to read, decode, and display any information that was saved by the sender, as shown in the following screenshot:

While we keep the block size in the platform format locally, we need to convert it into a unified representation when sending it out. We use the htonl function to do so:

  uint32_t encoded_size = htonl(size);

At this point, we can write the encoded size to the output stream:

  WriteData(fd, &encoded_size, sizeof(encoded_size));

The block's content is as follows:

  WriteData(fd, str, size);

The receiver, in turn, reads the size from the input stream:

 uint32_t encoded_size = 0;
ReadData(fd, &encoded_size, sizeof(encoded_size));

The size is encoded and cannot be used directly until the receiver converts it into a platform representation using the ntohl function:

 uint32_t size = ntohl(encoded_size);

Only after doing this, will it know the size of the block that follows and can allocate and read it:

 auto data = std::make_unique<char[]>(size);
ReadData(fd, data.get(), size);

Since the serialized data size is always represented as big-endian, the read function doesn't need to make assumptions about the endianness of the platform where the data was written. It can deal with data coming from any processor architecture.