You could add identifiers to the data you're sending:
enum StructID {
STRUCT_ONE,
STRUCT_TWO,
};
And send that before you send your data.
Uint16 id;
struct one dataOne;
id = STRUCT_ONE;
send(&id, sizeof(id));
send(&dataOne, sizeof(dataOne));
And on the receiving end:
char buffer[256];
unsigned nbRecv;
nbRecv = recv(buffer, sizeof(buffer));
if (nbRecv > sizeof(Uint16))
{
char * p = buffer;
Uint16 *pId = (Uint16*)p;
p += sizeof(*pId);
if (*pId == STRUCT_ONE)
{
struct one * pOne = (struct one *)p;
p += sizeof(*pOne);
if (nbRecv >= sizeof(*pId) + sizeof(*pOne))
{
// deal with pOne.
}
else
{
// Deal with too little data; pOne is incomplete....
}
}
else if (*pId == STRUCT_TWO)
{
struct two * pTwo = (struct two *)p;
p += sizeof(*pTwo);
if (nbRecv >= sizeof(*pId) + sizeof(*pTwo))
{
// deal with pOne.
}
else
{
// Deal with too little data; pTwo is incomplete....
}
}
else
{
// Error, unknown data.
}
}
else
{
// Deal with too little data....
}
Essentially you're defining a protocol at this point and the identifier is just a very simple "header" that exists to identify your data. A lot of protocols like this send the size of the data to follow as well so you can tell how much of the data there is before the next identifier/header.
Another common method besides integers is to send 4 ASCII characters, since they're easy to read when you are looking at raw data (Wireshark, hexdump, bytes in a debugger, etc). For your example I would suggest:
const char STRUCT_ONE_FOURCC[4] = { 'O', 'N', 'E', ' ' };
const char STRUCT_ONE_FOURCC[4] = { 'T', 'W', 'O', ' ' };
(Note, they're not strings per-say because they're not NULL terminated. They're fixed size character arrays.)
Note: in the above code I've left out most error checking and endian swap (to/from network byte order).
See Also: