Welcome!

Join our community of MMO enthusiasts and game developers! By registering, you'll gain access to discussions on the latest developments in MMO server files and collaborate with like-minded individuals. Join us today and unlock the potential of MMO server development!

Join Today!

Sending commands from client to server

Joined
May 16, 2011
Messages
650
Reaction score
327
Hi,

I have a server and client both written in C# WPF, using NET 4.0.
I'm trying to build a command structure to communicate between the client and server.

So far I'm using a basic string-based command structure, and I'm having a hard time making it work with the server.

The server receives a string command(ex: "REQUEST_ONLINEUSERS") from the client and sends the response back containing the data requested.
However, I'm having a hard time filtering multiple commands on the server. The command is converted to a byte array, then sent to the server. The server then reads the data and converts it back to a string. I then search for a specific ending tag, if it exists, it checks if it's a command by comparing the string.

This works and I can filter different commands, but I don't feel this is efficient and could cause problems later down the road. Is there a better way of identify commands from the client?
 
Retired. Don't PM.
Developer
Joined
Jan 5, 2009
Messages
593
Reaction score
741
Specify a data size coming from the client for your message identifier. Passing a string is horribly inefficient in anything except json (even then it's cancerous). Use an enumeration instead.
 
Joined
May 16, 2011
Messages
650
Reaction score
327
Specify a data size coming from the client for your message identifier. Passing a string is horribly inefficient in anything except json (even then it's cancerous). Use an enumeration instead.

Thanks, I'll try this method out. Curious though, would this make my server more secure, and is there a way to add encryption to the data being sent and received?
 
Ask me about Daoism
Loyal Member
Joined
Nov 6, 2010
Messages
1,560
Reaction score
393
Thanks, I'll try this method out. Curious though, would this make my server more secure, and is there a way to add encryption to the data being sent and received?

I recommend using message encapsulation. It's essentially where you use bytes instead of strings, per se. You get the data from the actual value of the bytes rather than what they convert to in ASCII. For this, you typically need to construct your packets a specific way. By the way, it's really intuitive :)

Here's an example of an efficient message structure, ideally all put together in a single byte array. I'll format it as it would look in a hex dump, and I'll show you what I'm doing.


Code:
0x72 0x00 0x00 0x72 0x00 0x0b 0x00 0x02 || 0x00 0x00 0x06 0x50 0x6c 0x61 0x79 0x65 
0x72 ||

Let's dissect it.

The first thing I'm doing is in byte[0-3], or the first three bytes. This is my protocol-specific header. 0x72 0x0 0x0 0x72 may be a bit long for a header, but if I make this a universally-required portion of each packet, then I can easily filter out malicious requests by doing nothing. This prevents random strings of characters (probably sent from LOIC) from even being processed if they can't be validated.

The next thing appears at byte[4-5], the next two bytes. I can get here by having an int be my "Read Index" (if I'm not using a Stream, which complicates matters), and simply jumping 4 bytes from 0. This part is the length of the buffer, MINUS the 6 bytes that make up the header. The value is 0x00 0x0b, which is 11 in decimal (base 10). Again, when I want to get to the next part of my packet, I can just do ReadIndex =+ 2; and I'll be able to do ByteArray[ReadIndex] to get to the next portion, which is..

0x0 0x2 0x0 0x0; This is a 4-byte block that I use to separate the 'parameters' of my packet. Having just gotten through the validation header and the length part of the header, the ReadIndex should now be at 6 (0 + 4 + 2), the first byte of the separator. Personally, I like using one. It helps me organize my structure. It's really up to you what the values are, and it's up to you whether or not you use one. 4 bytes is definitely a bit long, but hey, it works.

So if you wanted to be careful, read the next four bytes and check to be sure they're separators. For now, we'll just add 4 to ReadIndex and jump right over to the best part: the packet body.

This begins 4 bytes after the length bytes. The way I start it is by including a length byte, which measures how long the contents of the parameter will be. If you wanted to include another byte before or after this to indicate what TYPE of parameter it is (int/string/char), it's a good idea.

This is where ReadIndex becomes important, because not every field will have the same length. Personally, I'd make every header 2 bytes long. For this packet, I've chosen to make the contents of the packet the username. In the real world, you'd want to include a packet ID to tell the server what to do. For now, I chose to keep it simple. The 0x6 is the length of the username (6 'Player').

I hope this hasn't confused you, but it's really the best way to write a protocol. Strings can be slow, and I don't understand why people can't be arsed to deal with buffers. It's really easy once you get the hang of it, and programmers should know how to work them anyways!
 
Joined
May 16, 2011
Messages
650
Reaction score
327
I recommend using message encapsulation. It's essentially where you use bytes instead of strings, per se. You get the data from the actual value of the bytes rather than what they convert to in ASCII. For this, you typically need to construct your packets a specific way. By the way, it's really intuitive :)

Here's an example of an efficient message structure, ideally all put together in a single byte array. I'll format it as it would look in a hex dump, and I'll show you what I'm doing.


Code:
0x72 0x00 0x00 0x72 0x00 0x0b 0x00 0x02 || 0x00 0x00 0x06 0x50 0x6c 0x61 0x79 0x65 
0x72 ||

Let's dissect it.

The first thing I'm doing is in byte[0-3], or the first three bytes. This is my protocol-specific header. 0x72 0x0 0x0 0x72 may be a bit long for a header, but if I make this a universally-required portion of each packet, then I can easily filter out malicious requests by doing nothing. This prevents random strings of characters (probably sent from LOIC) from even being processed if they can't be validated.

The next thing appears at byte[4-5], the next two bytes. I can get here by having an int be my "Read Index" (if I'm not using a Stream, which complicates matters), and simply jumping 4 bytes from 0. This part is the length of the buffer, MINUS the 6 bytes that make up the header. The value is 0x00 0x0b, which is 11 in decimal (base 10). Again, when I want to get to the next part of my packet, I can just do ReadIndex =+ 2; and I'll be able to do ByteArray[ReadIndex] to get to the next portion, which is..

0x0 0x2 0x0 0x0; This is a 4-byte block that I use to separate the 'parameters' of my packet. Having just gotten through the validation header and the length part of the header, the ReadIndex should now be at 6 (0 + 4 + 2), the first byte of the separator. Personally, I like using one. It helps me organize my structure. It's really up to you what the values are, and it's up to you whether or not you use one. 4 bytes is definitely a bit long, but hey, it works.

So if you wanted to be careful, read the next four bytes and check to be sure they're separators. For now, we'll just add 4 to ReadIndex and jump right over to the best part: the packet body.

This begins 4 bytes after the length bytes. The way I start it is by including a length byte, which measures how long the contents of the parameter will be. If you wanted to include another byte before or after this to indicate what TYPE of parameter it is (int/string/char), it's a good idea.

This is where ReadIndex becomes important, because not every field will have the same length. Personally, I'd make every header 2 bytes long. For this packet, I've chosen to make the contents of the packet the username. In the real world, you'd want to include a packet ID to tell the server what to do. For now, I chose to keep it simple. The 0x6 is the length of the username (6 'Player').

I hope this hasn't confused you, but it's really the best way to write a protocol. Strings can be slow, and I don't understand why people can't be arsed to deal with buffers. It's really easy once you get the hang of it, and programmers should know how to work them anyways!

This is quite an interesting concept, easy to understand as well.
But would it be possible for an attacker to take this byte array and convert it back to a formatted string?
 

Ben

Developer - JS
Developer
Joined
Jul 6, 2013
Messages
1,224
Reaction score
506
On ur question of a hacker getting data, it's most likely he could get it pretty easy if he does a man in the middle and then logs the data send, he could just reassemble the packets and get the info, always encrypt ur data with a strong algorithm.

For encryption/decryption you can look into the cryptoServiceProviders of the encryption algorithm that you want to use, basic algorithms are on msdn.

You could encrypt ur data with aes and the key with public/private RSA keys, sign it and send it to the user.
 
Ask me about Daoism
Loyal Member
Joined
Nov 6, 2010
Messages
1,560
Reaction score
393
This is quite an interesting concept, easy to understand as well.
But would it be possible for an attacker to take this byte array and convert it back to a formatted string?

Yeah, unless you use encryption. Formatted string or not, it doesn't really matter what they convert it to once they have the packet. So, you'll want to use encryption probably.
 
Joined
May 16, 2011
Messages
650
Reaction score
327
On ur question of a hacker getting data, it's most likely he could get it pretty easy if he does a man in the middle and then logs the data send, he could just reassemble the packets and get the info, always encrypt ur data with a strong algorithm.

For encryption/decryption you can look into the cryptoServiceProviders of the encryption algorithm that you want to use, basic algorithms are on msdn.

You could encrypt ur data with aes and the key with public/private RSA keys, sign it and send it to the user.

Yeah, unless you use encryption. Formatted string or not, it doesn't really matter what they convert it to once they have the packet. So, you'll want to use encryption probably.

Thanks for the replies. I wrote a new command structure based on your inputs and it's working quite nicely; better than the previous.
 
Back
Top