2
\$\begingroup\$

I made a simple async networking server and I'd like to get some input on the code, whether things can be done better and whether the code is stable (able to hold more than 1000 connections without lag) for a MMORPG game.

GameNetworkListener.cs:

using System;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;

namespace Rain.Networking.Game
{
    public class GameNetworkListener
    {
        private TcpListener _listener;

        public async Task StartListening(int port)
        {
            _listener = new TcpListener(IPAddress.Any, port);
            _listener.Start();

            TcpClient lastClient;

            while ((lastClient = await _listener.AcceptTcpClientAsync()) != null) 
            {
                Console.WriteLine($"New connection from {lastClient.Client.RemoteEndPoint}");

                var gameNetworkClient = new GameNetworkClient(lastClient);
                await gameNetworkClient.StartReceiving();
            }
        }

        public void Stop()
        {
            _listener.Stop();
        }
    }
}

GameNetworkClient.cs:

using System;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace Rain.Networking.Game
{
    public class GameNetworkClient
    {
        private readonly TcpClient _client;
        private readonly NetworkStream _stream;

        public GameNetworkClient(TcpClient client)
        {
            _client = client;
            _stream = client.GetStream();
        }

        public async Task StartReceiving()
        {
            while (_client.Connected)
            {
                var bytes = new byte[512];
                var amount = await _stream.ReadAsync(bytes, 0, bytes.Length);

                var raw = Encoding.UTF8.GetString(bytes);

                if (amount > 0)
                {
                    if (raw.StartsWith("<policy-file-request/>"))
                    {
                        await SendData(Encoding.UTF8.GetBytes("<?xml version=\"1.0\"?>\r\n" +
                                                                 "<!DOCTYPE cross-domain-policy SYSTEM \"/xml/dtds/cross-domain-policy.dtd\">\r\n" +
                                                                 "<cross-domain-policy>\r\n" +
                                                                 "<allow-access-from domain=\"*\" to-ports=\"*\" />\r\n" +
                                                                 "</cross-domain-policy>\x0"));
                        _client.Dispose();
                    }
                    else
                    {
                        Console.WriteLine($"Received {raw}");
                    }
                }
                else
                {
                    _client.Dispose();
                }
            }
        }

        public async Task SendData(byte[] data)
        {
            await _stream.WriteAsync(data, 0, data.Length);
        }
    }
}

Following rules start the server:

_gameNetworkListener = serviceProvider.GetService<GameNetworkListener>();
await _gameNetworkListener.StartListening(30000);
\$\endgroup\$
2
  • 2
    \$\begingroup\$ Tell us please what else is your server doing besides being one... \$\endgroup\$
    – t3chb0t
    Commented Feb 16, 2019 at 18:37
  • \$\begingroup\$ "and whether the code is stable" Have you tried? With how many connections? \$\endgroup\$
    – Mast
    Commented Feb 17, 2019 at 11:04

1 Answer 1

1
\$\begingroup\$

I see two major issues when you want to use this code for a MMORPG game.

Exception Handling

Make your code robust against connection hick-ups (when connection goes down for a fraction). It's up to be the client to reconnect asap on connection loss (out of scope of your code). The server should dispose client connections on error in order to clean up resources.

Resource Management

The server does not care about the number of clients connected, nor does it own the life time scope of these connections.

I would expect the code below to close the connections.

public void Stop()
{
    _listener.Stop();
    // _connectedClients.ForEach(Disconnect); // cleanup resources
}
\$\endgroup\$

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.