TCP Games - Application Protocol
Let's first talk about how our clients and server are going to pass around messages/packets. To make this more structured than last time, we will be using JSON, which will only contain plaintext. Each JSON object will only have two fields, command
and message
.
command
: this tells the client/server how the packet should be processedmessage
: this adds some extra context for thecommand
. It may be an empty string sometimes
We have only three simple command
s for each type of packet:
bye
: this can be sent by either the server or the client. It notifies the other end that the sender is disconnecting gracefully.- If sent by the server to the client, the client should display the contained
message
and clean up its network resources - If sent by the client to the server, the server can choose what to do with the
message
(if there is one). It should also clean up any resources associated with the client
- If sent by the server to the client, the client should display the contained
message
: note that this is acommand
. It just sends a plaintext message- If sent by the server to the client, the client should print out the contents of the
message
field - If sent by the client to the server, the server can chose to ignore it. The client shouldn't be sending
message
packets anyways
- If sent by the server to the client, the client should print out the contents of the
input
: requests some input- If sent by the server to the client, the client should ask the user for some input
- the contents of the
message
field should be treated as a prompt for the user
- the contents of the
- If sent by the client to the server, this should only be in response to an
input
request- If this wasn't a response to a request, the server should just ignore the packet then
- If sent by the server to the client, the client should ask the user for some input
If you're a little confused, here's a diagram of how our apps will operate:
Packet class
Here is our Packet
class. ne sure to add it to both projects in your solution. The main reason we have this is so we can access the data in a more C# like way. We will be using Newtonsoft's Json.NET library for parsing.
How it will be sent over the network
Before we go and shove the Packet
into the internet tubes there is a little pre-processing that needs to be done first:
- Call the
ToJson()
method on thePacket
to get it as astring
. Then after that, encode it (in UTF-8) into a byte array - Get how many bytes are in that first byte array, then encode that number as an unsigned 16 bit integer into a second byte array. The resulting array should be exactly two bytes long
- Join those two arrays into a new one with the "length buffer," ahead of the "JSON buffer,"
That final byte array that we have is what will be sent over the network. This way whoever receives a Packet
knows how long it is.
You might be wondering why we have to do this. Here's the thing, TcpClient.Available
will report how many bytes have been received but not read yet, and only that. There is the possibility that two Packet
s may have been received before our app has had a chance to read from the NetworkStream
. This poses the question of how we will pull out the data into two separate Packet
s.
Since we are using JSON, we could match first level curly brackets. Instead, stuffing the length of the "true message," right before the actual message is a common technique that is used, and thus it's best that we practice that here.
I chose to use unsigned an unsigned 16 bit integer because it lets us have JSON strings that are almost 64 KB long; that's plenty of data for text based games. We could use just an 8 bit unsigned integer too but that will only give us 255 bytes max, so our messages we send would have to be quite tiny.