WinSock: Variable Packets

Started by
3 comments, last by MatrixCubed 23 years, 7 months ago
Forgive me if this is an utterly newbie question: What''s the best way to handle variable packet size receipt in WinSock? A previous post in another thread indicated that you could peek at the packet being received, and decide what to do based on it; is this a good way to handle variable sized packets? By variable sized, I mean the following: typedef struct _Velocity { DWORD dwType; DWORD dwSize; float X; float Y; float Z; } Velocity; typedef struct _TextMessage { DWORD dwSize; DWORD dwType; char szMessage[128]; DWORD dwColor; } Obviously I don''t want to pad each structure with extra bytes so that I can handle each packet the "easy way"... what about sending a ''type packet'' to the server that indicates the next received packet''s type will be? MatrixCubed
Advertisement
Good idea MatrixCubed! Maybe it''s good to send a WORD for type and a WORD for size. Together they make a nice DWORD...

But sometimes you need the size&type in combination with the rest of the packet, somewhere in a function.


I don''t know if it works, but what do you think of a C++ approach:

    class CPacket{  WORD wSize;  WORD wType;};class CPacketTime : public CPacket{  FILETIME Time;};class CPacketName : public CPacket{  char szName[32];};    


I handle packets sizes using predefined size table known both by the server and client, however i''ve found this way to be too resritctive. I suggest going with the type/size header, it''s more robust, as any future server can talk to any old client, though the new packets would be unprocessable ofcourse. The way i have it now i have to recompile a new client and server every time i change the packet size table or add a new packet type. I suggest using 2 bytes each for type and size, you don''t need a DWORD worth of header and types. Good Luck.

-ddn
Heh, well it''s not really the answer I was looking for I want to know how to handle reading/recv()()''ing different data-structures, assuming all structures have common fields (let''s assume WORD wType and WORD wSize).

Should I use recv() to ''peek'' (not read) a data-structure''s type, then read it into a buffer which is cast/memcpy''d to the correct structure? Should I attempt to send multiple packets, the first indicating the type, the second representing the actual data? (This way, I think both would need an ID right?)

I think I''m missing something important with all this; I might just wait to get my Network Programming in Windows book.


MatrixCubed
Here''s how I''ve seen it done, although this is perhaps not "the best" way, heh.

Basically, each client is assigned a text buffer of a pretty big size (something like 2k) which packets are read into. Each packet starts out with a "command byte" which specifies which packet it is (randomly making up numbers here) say 0x01 for logging in, 0x02 for creating new player, etc. Next comes two bytes (a DWORD I guess, I always forget how big a WORD and DWORD are which contain the size of the data FOLLOWING these two bytes, ie. the rest of the packet. So, a routine then just reads this much data into the socket''s buffer, and then when a function requires that data, it just pulls it out of the buffer rather than a predefined structure for each packet.

What is at each byte of the buffer is simply documented in a file somewhere. For example, the "login packet" might look like

BYTE command (0x01)
DWORD length (0xff)
char username[128]
char password[128]

or maybe

BYTE command (0x12) (move)
DWORD length 0x0f
BYTE direction
BYTE running (are we running or walking?)

and the buffer is just some char array like buffer[256]

so, looking at the documentation, you can tell that buffer[0] through buffer[128] will contain their username, and 129-255 will be their password. Or, in the second example, buffer[0] is the direction to move in, and buffer[1] is whether they are walking or running.


Does this make *any* sense? Cause I tend not to It might not be as easy to read as having a different structure for each possible packet, but if you''re in a game that can have over one hundred packets (like an online rpg, my area of study , then that could translate into a TON of structures to maintain, and a really big switch() statement saying

case move: readIntoMovementStructure
case login: readIntoLoginStructure

rather than just going by how long it says the packet is and using that.

Hope that helped

Anthracks

This topic is closed to new replies.

Advertisement