Jump to content

Recommended Posts

No, it is likely that the game traffic would be encrypted.

 

 

Side note, if you're going down the path of hosting an unlicensed server for a popular game, you might want to consider the legal ramifications of that.

 

 

 

But... on a more curious note: what game did you check?  You might be able to find details on decrypting the traffic.

I checked StarCraft 2

 

I am not sure you quite understand what the server is meant for... It is for game programmers to make their own online multilayer game, it is not for hosting any popular game... at least not popular yet. For example, say you wanted to make a multilayer  tic-tac-toe game, but didn't have a server to host the game. That is where I come in, you connect to my server which would know about all the players playing your game and allow you to connect with them to play a game of tic-tac-toe, or what ever type of game you decided to make.

Ahhh, I did misunderstand.  I thought you were trying to code a server for an existing client.

 

Nope...

 

You have quite the bit of planning, research and development ahead of you...

 

I am starting to realize that :) But... that is ok!

 

I already have a chat server, so I will be taking that for a game chat server, then making a game server by modifying that.

 

I am not sure, but I am thinking plain text will be my starting point, and see how that works out. Most (if not all) languages can break up text that is in a particular format so it can be read.

 

for example:

MOVE[x=100,y=250]

could tell an object to move to point (100,250) on a map

If you want to send data in text like that it makes more sense to me that you would use something like XML instead of creating your own format and parsing mechanism. I'm sure you can find XML parsers in whatever language(s) you'll be working with instead of having to create something from scratch on your own. Not only that, but by using a popular format like XML you make it more portable.

 

Personally when I have to send data back and forth like this I usually send raw bytes. Instead of having to specify that x=something and y=something else I have the receiving end expecting certain data in a certain order. For example, say that I'm processing a certain packet that I know is a "move character" packet (this can be determined from previous bytes in the packet). In my protocol I can specify that the X and Y values are both shorts (2 bytes). If as per our protocol we know that the first thing we're reading is the x value, then we can just read 2 bytes and we have our x value. If we also know that the next thing in the packet is the y value then we can just read two more bytes and then we have that. This way we're sending less data back and forth. That's not to say that XML is a bad method though; there are many games that do use XML for transmitting their data back and forth.

I also asked here, and this reply seems similar to what you are saying AlexWD:

http://www.gamedev.net/community/forums/topic.asp?topic_id=578377&whichpage=1

 

The problem is, I don't really understand this. Do you have any helpful links?

 

The reason I don't want to use XML, is that it can become rather bulky for online gaming, but that also depends on the game.

I can't think of any links offhand. You can try googling, but I'm guessing you've already done that. The idea behind it really isn't that complicated. I'll give you an example in PHP seeing as this is a PHP forum and you mentioned that you'll either be doing this in Python (a language I have no experience with) or PHP, but I have to warn you.. I've attempted to use PHP for socket servers in the past and I've discovered that it scales absolutely terribly and isn't a good solution for even relatively small games. I'm guessing it's due to the overhead in the socket functions that when used frequently is exposed. (The scaling issues were noticeable with as little as 5-10 clients who weren't sending packets that fast and all packets were of very small size).

 

Anyway.. Here's how I typically setup my protocols.

 

[first 2 bytes] - a short that defines the length of the packet

["family" byte] - This byte sets the "family" of the packet. An example of a family might be "player"

["action" byte] - This byte sets the "action" and might be something like "move"

[counter byte] - This is a counter byte that increments after each packet and is reset at a certain point. It's main purpose is to make sure that someone can't just catch the packet and resend it over and over. Since (assuming you're using some kind of encryption) the person couldn't make their own packets. It's also important to note that the client sends this to "check in" and the packets going from server->client won't contain this byte.

[rest of the bytes]

 

What I typically do is create two classes for building and reading packets: "PacketBuilder" and "PacketReader". In PHP you can take advantage of the pack and unpack functions for all your binary packing. For example, packing the number 9745 into a 2 byte representation. In other languages that don't have such utilizes, for example, C/C++, you'll have to do it yourself. It's not hard and can be accomplished through some bit-shifting tricks. Anyway, an example of a PacketBuilder class in PHP could look like this:

 

class PacketBuilder {
private $_family;
private $_action;
private $_data;

public function __construct($family, $action) {
	$this->_family = chr($family);
	$this->_action = chr($action);
}

public function addChar($char, $signed = true) {
	$this->_data .= pack($signed ? 'c' : 'C', $char);
}

public function addShort($short, $signed = true) {
	$this->_data .= pack($signed ? 's' : 'S', $short);
}

public function addInt($int, $signde = true) {
	$this->_data .= pack($signed ? 'i' : 'I', $int);
}

public function addString($string) {
	$this->_data .= $string . "\0"; // null terminated C-style strings
}

public function get() {
	return str_split(
		pack(
			's',
			strlen($this->_data) + 2
		) . 
		someEncodingFunction(
			$this->_family . 
			$this->_action .  
			$this->_data
		),
		250
	);
}
}

 

Most of it is pretty self-explanatory because it's mostly just using the pack PHP function, but some of it is not. In the get() function that returns the packet the use of str_split might be confusing. The reason it's necessary to split the packet into multiple parts if it's large is because of the MTU (Maximum Transmission Unit). You can read more about it in the link provided, but it's not that important for our purposes. All you need to know is that if you attempt to send packets of much more than 250 bytes you'll run into problems. For that reason you'll need to split them up and send them separately. Of course, you're client will have to be prepared to receive packets in parts instead of all at once (it will also need to be prepared to receive packets musted together, but that's another issue).

 

And then your PacketReader class might look something like this:

 

class PacketReader {
private $_family;
private $_action;
private $_counter;
private $_valid = true;
private $_data;

public function __construct($data) {
	$this->_data = SomeDecodingFunction($data);

	if(strlen($this->_data) < 3) {
		$this->_valid = false;
	} else {
		$this->_family = ord($this->_data[0]);
		$this->_action = ord($this->_data[1]);
		$this->_counter = ord($this->_data[2]);
		$this->erase(3);
	}
}

public function getFamily() {
	return $this->_family;
}

public function getAction() {
	return $this->_action;
}

public function getCounter() {
	return $this->_counter;
}

public function isValid() {
	return $this->_valid;
}

public function getChar($signed = true) {
	if(strlen($this->_data) >= 1) {
		$char = current(unpack($signed ? 'c' : 'C', $this->_data[0])));
		$this->erase(1);
		return $char;
	} else {
		return 0; // error
	}
}

/*
	getShort() and getInt() methods..
*/

public function getString() {
	$nullPos = strpos($this->_data, "\0");
	$string = substr($this->_data, 0, $nullPos);
	$this->erase($nullPos + 1);
	return $string;
}

private function erase($c) {
	$this->_data = substr($this->_data, $c);
}
}

 

You would have some function to take care of processing the packets coming in, making sure that if you received part of a packet it would wait to get the other parts, split apart packets that arrived mushed together, etc.. Then once that's all done assume that the variable $packet contains the packet data without the first 2 bytes (the length of the packet that was stripped off). You could then do something like this:

 

$reader = new PacketReader($packet);

switch($reader->getFamily()) {
case PACKET_PLAYER:
	switch($reader->getAction()) {
		case PACKET_MOVE:
			/*
				Assume that the data coming from the client is in the following manner (ignoring the family/action/counter, which we've already delt with):
				byte 1-4 (int) - player id (now this isn't technically needed because you should be able to get it from the socket, but for this example we'll assume it comes from the client
				byte 5-6 (short) - new X coordinate
				byte 7-8 (short) - new Y coordinate
			*/
			$playerThatMovedID = $reader->getInt();
			$newX = $reader->getShort();
			$newY = $reader->getShort();

			/*
				Now we construct the new packet that will get sent to the other players
			*/

			$builder = new PacketBuilder(PACKET_PLAYER, PACKET_MOVE);
			$builder->addInt($playerThatMovedID);
			$builder->addShort($newX);
			$builder->addShort($newY);

			/*
				Now we can send this packet to all the right players.
			*/
		break;
		default:
			// Unknown packet action with family of PACKET_PLAYER
		break;
	}
break;
default:
	// Unknown packet family
break;
}

 

Networking certainly isn't the easiest topic in programming and this post doesn't, nor was it intended to, fully go over the entire process. It hopefully just sheds some light on some small parts of it. Namely the act of constructing and reading packets using using binary as your transmission type.

  • 2 weeks later...
This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.