I'll try to keep this short. So I'm making a network interface which, inherently will be used for creating simple video games. I initially began designing it in TCP but I found it to be too slow so I switched to UDP.
My current idea is this: I want to send structs, where each struct corresponds to a specific message. Of course, I need to know the size of the struct when the server or client receives it. I fix this by first sending a standardized struct which contains the type of struct which is coming next, and then handle that accordingly. So I'll have something like a shared header file between the client and server which would look like this:
enum data_type { PLAYER_MESSAGE, PLAYER_LOCATION};
struct enum_type {
int nClientID;
data_type data_identifier;
};
struct player_message {
char message[128];
};
struct player_location {
int x, y;
};
Then, in the function that receives data sent by the other client I would do something like this:
enum_type enum_check;
recvfrom(socket, (char*)&enum_check, sizeof(enum_type), 0, (struct sockaddr*)&client, &client_length);
switch(enum_check.data_identifier)
{
case: PLAYER_MESSAGE
player_message temp_message;
recvfrom(socket, (char*)&temp_message, sizeof(player_message), 0, (struct sockaddr*)&client, client_length);
//Print message
break;
case: PLAYER_LOCATION
player_location temp_location;
recvfrom(socket, (char*)&temp_location, sizeof(player_location), 0, (struct sockaddr*)&client, &client_length);
//move player
break;
}
The system works pretty well with all sorts of messages and also behaves decently under (some) stress. The problem of course is that every single client would be using the same recvfrom to first check the message type and then to handle it accordingly. In short, I don't trust this system one bit because it makes too many assumptions. It makes the assumption that a receive giving a message type is always followed by the correct message. With UDP, you can never really guarantee this is the case, which is leaving me stumped. (I am also aware of the problem with endianness and computer architectures with this approach, but I'm side-lining that for now.)
I figured a quick and easy approach would be to have only one type of struct, including the client ID, how to use its data (enum), room for around 10 numbers as well as some text. This way I would not have to make assumptions but would of course send tons of needless data constantly (which wouldn't be a problem if bandwidth isn't really an issue, but it seems like a pretty dumb solution nonetheless).
Any suggestions here? I've contemplated just using a network library such as ENET (then again, wouldn't I get the same problems trying to send structs?) but that seems like such a defeat. I'm only doing this to learn after all.