network parsing

Started by
9 comments, last by Brandisco 22 years, 8 months ago
Is it possible using the winsock to have clients send structs to the server and vice versa. I saw an example where someone sent the memory address of the struct and then in the server (or client) it read the buffer into the memory address of its struct (both structs are identical -- with the same members). If this method works then no parsing would be required but lack some power. In visual basic I used the functions InStr(which would return the location of a string (int) inside a string given 2 strings) and Mid (which would return the part of the string -- you tell it the string and the start and end locations). With these 2 functions I was able to parse all network data in a multiplayer. Data that looked like this: user_join_game:username:password ( i could simply parse the data between colons) I am wondering if the first option is possible and if there are any standard C functions like the 2 I mention in paragraph 2. Thanks, Brandon
Advertisement
There are standard C functions to twiddle strings, though I haven''t used any of them in years except strcpy.

It''s fairly straight forward to create a packet out of a C struct, it''s a process called ''serialization''. Instead of sending text and parsing it, you send binary data and parse that. It''s usually easier to code, and orders of magnitude smaller & faster.

DWORD* pdwSetPacketID = (DWORD*)&packetbuffer[bufferbytes];pdwSetSize = CMyPacket::s_dwPacketID;bufferbytes+=sizeof(DWORD);memcpy(&packetbuffer[bufferbytes], &MyPacket, sizeof(CMyPacket));bufferbytes+=sizeof(CMyPacket); 


If the packet has pointers it gets more complicated.

Magmai Kai Holmlor
- Not For Rent
- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
You can''t just send the memory address of something over a network link and expect it to link, because the other end of the link is in a different process (and thus address) space, let alone a different computer, and the pointer your sending will prolly point to invalid memory at the other side. You''d cause heap / stack corruption or segfaults (Access Violations for you Windows people )

Now, Magmai already answered the more important part. However, I''d like to add something. For example, imagine a server<->client relationship where the same strings are sent back and forth very often. Instead of sending the entire string every time, you could have the server send a string table down to the client, and after that you''d just send an offset into the string table. You could even add messages to extend the string table. Beware of collisions if both the server and the client may add to the table. In that case, you may want to have two string tables, one which is maintained (owned) by the server, and one for the client.


BTW Magmai: You''ve _never_ used standard C functions in years? WTF have you been using? CString?
Or maybe you just never had to write a config parser...

cu,
Prefect

Resist Windows XP''s Invasive Production Activation Technology!
One line of sourcecode says more than a thousand words.
Widelands - laid back, free software strategy
test
I think I know exactly what you are talking about. Just do all your network byte reordering, cast the structure into a byte pointer and on one side. On the other side, make sure you have the equivalent structure and just receive it into that structure. The variables should correspond to each other if you declare the variables in the same order within the structure. Do your network byte reordering again and presto it works. Also, make sure you align your bytes.
Exactly.

For the byte packing thing, do a
#pragma pack(1)
before all the critical structure declarations, and a
#pragma pack()
afterwards to restore to normal packing.
Of course you could also use pack(4) or whatever, but that would potentially waste space, which is still critical over the inet. You wouldn''t need it either if you only used one compiler. But as soon as you''re using different compilers, things might break (even different versions might break it).
Note that the same applies when you declare structures for your file types.

Note that you only have to do the network byte ordering stuff if you''re going to port your game to a platform with different endianness (I always forgot which endian type is which). As long as you stay on an i386 you can save your time and not do it. (Even if you intend to port to a different platform later, you can still use Intel byte ordering anyway.. you just have to do the byte reordering on that other platform).

cu,
Prefect

One line of sourcecode says more than a thousand words.
Widelands - laid back, free software strategy
No need to reorder the bytes unless you''re trying to send data from a x86 to a Mac or something...

You need to add a packet/message identitifer as the first item in the packet so you know what kind it is. Then you need a big ''ol switch statement, or a fancy message-map to ''crack'' and handle the packets.

If I need to twiddle a config file I use the pre-canned Window''s .ini file reader/writers. Very easy, very flexible, already done; all around .ini files are verra niace. If it''s not .ini then it''s in the registry... so no I haven''t written a text parser since my freshman year in college... and I usually use sprintf to put together strings otherwise.



Magmai Kai Holmlor
- Not For Rent
- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
If you want to get really fancy, you should try using factories for the message types. I''ve seen an article on factories used for network message parsing on gamedev some months ago...

Basically, it''s a "technology" which is better known from "business" programming, and involves one C++ class derived from a pure base class for each message type, and a template class which is instantiated globally once per message type class. This template then adds "its" C++ class to a global linked list of message types, or similar.

cu,
Prefect

One line of sourcecode says more than a thousand words.
Widelands - laid back, free software strategy
I read that same article on pluggable class factories. I thought the idea sounded good on paper, but implementation was ugly and it didn't really gain you anything.

As far as this goes, I have a system that does pretty much exactly what Brandisco is asking. The only difference is that I'm using DirectPlay. As for how it's done, just make sure you don't use pointers in your message structures. If you want to use a string, declare it as a character array, not a character pointer. If you declare it as a pointer, it won't show up in a contiguous region of memory with the structure. Also, put your largest strings that may vary in length at the end of the structure, then compute the size of the structure to send based on the length of that string.

Here's some example code. The first structure is the base message which all other messages are derived from. The second is a structure I use to send an exported CryptoAPI key blob to set up my encryption:

    typedef struct DP_MSG{	USHORT	nType;	USHORT	nSize;	DP_MSG(USHORT type){		nType = type;		nSize = sizeof(DP_MSG);	}}*PDP_MSG;typedef struct DP_MSG_KEY : DP_MSG{	BYTE	byData[DP_MAX_KEY_LEN];	DP_MSG_KEY(USHORT type, PBLOB_INFO pBlob) : DP_MSG(type){		ZeroMemory(byData, DP_MAX_KEY_LEN);		if(pBlob->dwSize <= DP_MAX_KEY_LEN)			memcpy(byData, pBlob->pbData, pBlob->dwSize);		nSize += (USHORT)pBlob->dwSize;	}}*PDP_MSG_KEY;    


When I want to send the structure using DPlay (and it would be the same with Winsock) I just pass the address of the message structure, and the length of the data to send. On the receiving end, I receive the message, cast to PDP_MSG and switch based on the type of message.

Hope that helps.

Edited by - JonStelly on August 14, 2001 10:35:15 AM
Can anyone tell me whats wrong with the code below?

buffer = "xy:23:23:23:23"

Where the 23's could be any integer. This is part of the code for my game of networked pong.

I read the incoming packet from the server into the buffer string and then call parse code to parse it for me. I try to parse it down so I know where to draw the enemy's paddle.

Thanks

  volatile int ex1 = 450, ex2 = 400, ey1 = 100, ey2 = 103;void parse_code() {	char *funct;	memcpy(funct, buffer + 1, strstr(buffer, ":") - 1);	memcpy(buffer, strstr(buffer, ":") + 1, strlen(buffer));	if (strcmp(funct,"xy") == 0) {		memcpy(ex1, buffer + 1, strstr(buffer, ":") - 1);		memcpy(buffer, strstr(buffer, ":") + 1, strlen(buffer));		memcpy(ex2, buffer + 1, strstr(buffer, ":") - 1);		memcpy(buffer, strstr(buffer, ":") + 1, strlen(buffer));		memcpy(ey1, buffer + 1, strstr(buffer, ":") - 1);		memcpy(buffer, strstr(buffer, ":") + 1, strlen(buffer));		ey2 = buffer;	}}   


Edited by - Brandisco on August 16, 2001 9:46:35 AM

This topic is closed to new replies.

Advertisement