0
\$\begingroup\$

I've been working on an 2D-RPG for a while and I recently decided to make it into an MMO (not really massive, but multi-player). Anyways, I'm attempting to write a game server in C#. Yes, I know I could use a commercial solution like SmartFoxServer or Photon, but I want to make it a learning curve by going through the pain of doing it myself. It's pretty much going to be a simple zone-room architecture that handles events and sends position updates a few times in a second.

A lot of articles I read recommended using UDP but I'm limited to TCP because my client will be a browser based flash file. I've pretty much worked out in my head how I want everything to work, the binary protocol and etc, but I'm stuck at the beginning.

I'm not quite sure how to start. I've read about 3 different types of socket communication in C#:

  1. Blocking - I know I can't use this because the main thread will be blocked when accepting connections and etc.
  2. Non-Blocking
  3. Asynchronous

I don't know which is the better, or the obvious choice for what I'm trying to do. I want the server to be scalable and handle a few hundred concurrent connections. I tried to study SFS and it seemed like it had multiple thread pools, for accepting connections, receiving data and sending data respectively. I had it in my mind that I would do it the same way and use the ThreadPool class, but I'm not sure of the difference between non-blocking and asynchronous.

Can someone clarify to me the difference between the two and which one is the better choice for me. I would appreciate any link you think might help as well.

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

Non-blocking is basically the same thing as asynchronous: if you use the async features of .Net sockets you will get non-blocking code for free.

I doubt you are using C# 4.5 so you will need to resort to the 'older' way of doing non-blocking IO. The following is a snippet which deals with how to stream data from a TCP connection (you will likely want to use UDP, but the core principles are the same):

private Socket _socket;
private ArraySegment<byte> _buffer;
public void StartReceive()
{
    ReceiveAsyncLoop(null);
}

// Note that this method is not guaranteed (in fact
// unlikely) to remain on a single thread across
// async invocations.
private void ReceiveAsyncLoop(IAsyncResult result)
{
    try
    {
        if (result != null)
        {
            int numberOfBytesRead = _socket.EndReceive(result);
            if(numberOfBytesRead == 0)
            {
                OnDisconnected(null); // 'null' being the exception. The client disconnected normally in this case.
                return;
            }

            var newSegment = new ArraySegment<byte>(_buffer.Array, _buffer.Offset, numberOfBytesRead);
            OnDataReceived(newSegment);
        }
        _socket.BeginReceive(_buffer.Array, _buffer.Offset, _buffer.Count, SocketFlags.None, ReceiveAsyncLoop, null);
    }
    catch (Exception ex)
    {
        // Socket error handling here.
    }
}

Also remember that dealing with 100's of users (as opposed to 1000's) is actually pretty easy. If you keep your networking code and your game code on different threads you might even be able to get away with blocking sockets (non-blocking/async was involved in solving the C10K problem).

I have a blog post on the matter which you might find useful.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .