Typically, you define your message format as something like:
<type> <length> <... data ...>
One byte each for "type" and "length" gets you pretty far.
Thus, your actual UDP datagram would look like:
<type> <length> <data * length> <type> <length> <data * length> ...
This allows you to figure out what each message is, and how long it is (so you can find the next message.)
The header typically will contain an application-specific identifier, serial number (for de-duplication, etc) and perhaps server time information and maybe a checksum, if you don't trust the pretty dumb UDP checksum algorithm, or want to do cryptographic signatures or whatever.
For example, here's one possible format:
<id0> <id1> <serial> <acklast> <ackseq> <timebyte>
id0 and id1 are bytes that you choose, that mean that you can tell your packets apart from random packets that some application might send on your particular port. (This is most important for broadcast, but useful for regular UDP as well)
"serial" is simply incremented by 1 for each UDP packet sent by the sender, and wraps around from 255 to 0.
"acklast" is the serial number of the last packet received from the other end, used for knowing which packets made it. <ackseq> is how many packets before <acklast> were received without any drops, capped at 255.
Note that this does not allow you to positively identify packet sequence numbers that were NOT received, but you typically don't need that.
Finally, "timebyte" is perhaps something like the current server clock in units of ten milliseconds, again wrapping around from 255 to 0. This can be used for clock synchronization, etc.
Edited by hplus0603, 29 September 2012 - 06:38 PM.
Typically, you send more than one message in a single UDP datagram.