views:

243

answers:

5

Hi all,

I am creating a protocol to have two applications talk over a TCP/IP stream and am figuring out how to design a header for my messages. Using the TCP header as an initial guide, I am wondering if I will need padding. I understand that when we're dealing with a cache, we want to make sure that data being stored fits in a row of cache so that when it is retrieved it is done so efficiently. However, I do not understand how it makes sense to pad a header considering that an application will parse a stream of bytes and store it how it sees fit.

For example: I want to send over a message header consisting of a 3 byte field followed by a 1 byte padding field for 32 bit alignment. Then I will send over the message data.

In this case, the receiver will just take 3 bytes from the stream and throw away the padding byte. And then start reading message data. As I see it, he will not be storing the 3 bytes and the message data the way he wants. The whole point of byte alignment is so that it will be retrieved in an efficient manner. But if the retriever doesn't care about the padding how will it be retrieved efficiently?

Without the padding, the retriever just takes the 3 header bytes from the stream and then takes the data bytes. Since the retriever stores these bytes however he wants, how does it matter whether or not the padding is done?

Maybe I'm missing the point of padding.

It's slightly hard to extract a question from this post, but with what I've said you guys can probably point out my misconceptions.

Please let me know what you guys think.

Thanks, jbu

+2  A: 

If word alignment of the message body is of some use, then by all means, pad the message to avoid other contortions. The padding will be of benefit if most of the message is processed as machine words with decent intensity.

If the message is a stream of bytes, for instance xml, then padding won't do you a whole heck of a lot of good.

As far as actually designing a wire protocol, you should probably consider using a plain text protocol with compression (including the header), which will probably use less bandwidth than any hand-designed binary protocol you could possibly invent.

TokenMacGuy
+1 to use text for readability, debugging, logging, extensibility, etc., and/or compressed text to minimize size; a binary format could well be "premature optmization". A binary format *may* optimize CPU utilitization and memory, though, which was an important consideration for TCP (and may or may not be important for a home-grown protocol/application).
ChrisW
+2  A: 

I do not understand how it makes sense to pad a header considering that an application will parse a stream of bytes and store it how it sees fit.

If I'm a receiver, I might pass a buffer (i.e. an array of bytes) to the protocol driver (i.e. the TCP stack) and say, "give this back to me when there's data in it".

What I (the application) get back, then, is an array of bytes which contains the data. Using C-style tricks like "casting" and so on I can treat portions of this array as if it were words and double-words (not just bytes) ... provided that they're suitably aligned (which is where padding may be required).

Here's an example of a statement which reads a DWORD from an offset in a byte buffer:

DWORD getDword(const byte* buffer)
{
  //we want the DWORD which starts at byte-offset 8
  buffer += 8;
  //dereference as if it were pointing to a DWORD
  //(this would fail on some machines if the pointer
  //weren't pointing to a DWORD-aligned boundary)
  return *((DWORD*)buffer);
}

Here's the corresponding function in Intel assembly; note that it's a single opcode i.e. quite an efficient way to access the data, more efficient that reading and accumulating separate bytes:

mov eax,DWORD PTR [esi+8]
ChrisW
+1  A: 

Oner reason to consider padding is if you plan to extend your protocol over time. Some of the padding can be intentionally set aside for future assignment.

Another reason to consider padding is to save a couple of bits on length fields. I.e. always a multiple of 4, or 8 saves 2 or 3 bits off the length field.

Case Larsen
but probably, YAGNI :)
Jeffrey Kemp
+1  A: 

One other good reason that TCP has padding (which probably does not apply to you) is it allows dedicated network processing hardware to easily separate the data from the header. As the data always starts on a 32 bit boundary, it's easier to separate the header from the data when the packet gets routed.

marcush
+1  A: 

If you have a 3 byte header and align it to 4 bytes, then designate the unused byte as 'reserved for future use' and require the bits to be zero (rejecting messages where they are not as malformed). That leaves you some extensibility. Or you might decide to use the byte as a version number - initially zero, and then incrementing it if (when) you make incompatible changes to the protocol. Don't let the value be 'undefined' and "don't care"; you'll never be able to use it if you start out that way.

Jonathan Leffler