Monday, 2 July 2012
XNA Socket/UDP Server
The other day I was discussing with a friend (Jeremy) MMOG's and how we might go about writing one, we then went on to chat about MUD's we had written in the past and so lead me to the idea of creating a socket server; as I had had some experience of writing sockets in C++ and VB I thought I would give it a go in C#. Turns out there are a tone of articles on line that you can reference for this sort of stuff. Having written most of the socket side another friend of mine (Chr0n1x) suggested looking at writing a UDP server as that's what is mostly used in games development these days.
If you are not up on Sockets and UDP, take a look here for a pros and cons.
I guess your first question will be, what is wrong with using the Live networking that comes with XNA 2.0, my answer is, nothing, by all means use it, but if you don't want to go through the Live network, then you will have to write your own server and client system. This is a way to start doing that. This post only has the basic connection management, you will naturally have to add the messaging system that your game will need but you can also see a rudimentary example of this in the way the server accepts clients and adds them to the client list.
Your next question will by, why put it in an XNA project, why not, means I don't have to write the message pump and just create it as a Game Component and write the rest around it. Also, you could then have the server in the game code as well and then have one game serving with the others as clients on a LAN or even if you have a static IP, serve it on line (may be some security issues there :P)
Well here is how I have laied it out in this example.
As you can see in the class diagram above, there four classes, two enumerated types and six delegates.
BaseServer has all the basic items both server types will need; events to inform the user that connections are being attempted, dropped and that data has been received etc.. also basic fields and related properties that both servers will use like MachineName and Port.
SocketServer is the class used to create a socket server (well named or what eh?). It has a few extra fields and properties for the serving IP and a TcpListener to obtain connections to it. It also overrides some of BaseServer methods to get extra things done in those methods.
UDPServer is the class (you guessed it) used to create a UDP server. As with the SocketServer it has extra fields and properties with overrides to BaseServer to do the jobs it needs to to as a UDP server.
ClientData is used to store your client/player data, it has basic authentication for adding a server generated Guid to uniquely identify each user. In this example I have not added any other data objects than are needed to bind clients to the server.
The enumerators are my stab at a very basic messaging protocol, you can use this, extend it or even throw it out and create your own.
MessageType is the main message type so I can split out messages that are to passed strait on to another user like an in game message or if it is data that is going to change an item or items in the world it's self etc..
MessageSubType, so you have a min message type and these can then be split down further, so staying with a player to player message, one message could be to all on players like an OOC (Out Of Character) message or could be a personal message sent to a single player in game.
The delegates define the event signatures that a user of the classes can use to wire up events from the server.
ConnectionAttemptEvent is fired each time a client/player tries to connect to the server.
ConnectionDroppedEvent is fired when a clients connection is dropped or lost.
DataReceivedEvent is fired when data comes into the server from a client.
ErrorEvent is fired when an error occurs on the server.
ServerStartEvent is fired when the server starts listening for clients.
ServerStopEvent is fired when the server is stopped.
In the example project you can download there is also a test client, all that this client does is connect to the service and can send text messages to it, nothing else, it's pretty rough realy. The server example using the objects described above just allows and acknowledges connections to it and drops them if they are inactive for the default ClientTimeOut, which I set at an arbitrary 30 seconds.
You can get the example code here.