NetworkDesign

From Arianne
Revision as of 20:53, 25 February 2010 by imported>Hendrik Brummermann
Jump to navigation Jump to search



Please note: This page explains the low level network communication. You don't need to bother with these implementation details if you want to use Marauroa to write a game. We document the network design anyway for contributor to Marauroa itself. And it is helpful for people porting Marauroa to other programming languages.

Messages

Marauroa uses messages to communicate between client and server. The messages sent from the client to the server are prefixed with C2S and the ones sent from the server to the client use the prefix S2C.

Each message is implemented in its own Java class in the package marauroa.common.net.message. You can lookup up the details about every message in the javadoc. If you want to port Marauroa to another programming language, you will need know how the message are serialized exactly. The easiest way to learn that is to look at the source code of the readObject() and writeObject() methods.

There are for different client states of the game: connected, logged in, in game, logged out. Depending on the state different messages are valid:

State connected

 
Messages used to securely login.


State logged in

 
Selecting a character and transmitting world meta data.


State in game

 
Messages sent while the game is active.


Logging Out

 
The client sends a logout request and the server accepts or denies it.


Transmitting Messages over TCP

The idea behind arianne's network protocol is to use a single stream of TCP packets between the server and the clients. Different kinds of in-game actions create different types of messages that are then interpreted at the opposite side in to meaningful data.

TCP Packet Format

The network system is based on Messages being transmitted using TCP. There are two types of data stream; one from the Server to the Client and another one from the Client to the Server.

TCP Client to Server communication stream

The messages are sent one after each other over the TCP stream. TCP takes care of sorting the packets and retransmitting lost ones..

Each message is composed of:

  • Protocol version ( 1 byte )
  • Type of Message ( 1 byte )
  • Client ID ( 4 bytes )
  • Rest of Message

TCP Server to Client communication stream

Each message is held in one or more UDP Packets and the UDP Packet format is as follows:

TODO: update this to reflect the new TCP based protocol 1st UDP Packet is composed of:

  • Total number of packets (1 byte)
  • Position of this message (1 byte)
  • Signature of the message (2 bytes)
  • Protocol version (1 byte)
  • Type of Message (1 byte)
  • Client ID (4 bytes)
  • Rest of Message

All other UDP Packets making up the one message are composed of:

  • Total number of packets (1 byte)
  • Position of this message (1 byte)
  • Signature of the message (2 bytes)
  • Rest of Message (up to 1497 bytes)

Messages are sent from the Server by simply serializing them. So the message itself contains the protocol version, the type of message and the Client id.

Receiving the message is a bit more complex. First we need to determine that we are running a compatible version of the protocol by comparing the protocol version with the expected version in the message. Once we have agreed that the protocol is compatible we read the type of message and we ask the Message Factory ( see RolePlayingDesign) to build an object of that type with the corresponding data. Once the message is built we simply store it in a queue of incoming messages waiting to be processed.

Network Manager

The Network Manager is our router that sends and receives messages to and from the network. The manager exposes the interfaces that allow:

  • Reading a message from the network
  • Sending a message to the network
  • Finalizing the manager

The read operation is a blocking type operation so we have two options, either polling (i.e. continually checking if data is there) or blocking (i.e. only processing when data is actually available, otherwise sleeping).

We choose blocking because we don't want to waste CPU time polling the network for messages, we just want to sleep until messages are available. Hence we create a Thread to read from the Network, let's call it NetworkManagerRead.

Writing messages to the network can be simply coded as a method of Network Manager, as write is an operation that is non blocking by nature.

The NetworkManager opens a Socket from which it will receive all the messages from the network. It will also write all the outbound messages to the network from this same socket. Note: Both write and read use the same Socket.

To encapsulate all this we create both the Read and Write methods as inner classes of Network Manager.

NetworkManager
  {
  socket
  messages
  pendingToSendMessages

  NetworkManagerRead isa Thread
    {
    read socket
    build message
    store in messages
    }

  NetworkManagerWrite isa Thread
    {
    get from pendingToSendMessages
    serialize message
    send socket
    }
  }

As you can see, messages are stored in a list when they are received. Hence access to the list must be synchronized.

Now lets get back to the interface as exposed to other objects. The write method is immediate, just call it with the message to send, making sure that you have correctly filled SourceAddress and ClientID. The message will then be sent to the Client.

The read method is blocking, when you call the read method it either returns a message from the queue or if the queue is empty the thread blocks (sleeps) until one arrives.

That is the basic idea of the Network Manager. Note that the manager just sends the stream of packets once and doesn't confirm if any of the messages are received. TCP takes care of that.