0

Context:

I want to make a multiplayer game with unity and i would like to make dedicated servers for players to be able to open their own server. I haven't made the game yet, i'm just experimenting with my server and a test client. The server is a C# console using System.Net (as the client for now). For now i just want to make a nice architecture for the future real server.

Problem:

In a game, i would assume there is a lot of different types of packets that the player can send and receive to/from the server. And i'm trying to find a scalable/clean way to manage them. But as you can imagine it's not going so well...

How does it work right now:

For now when the client want to send data to the server it sends it this way:

[PacketCode]Message

Where: PacketCode -> is a code i defined for every type of packet and Message -> is just a string for now

When the server receive the message it call the Filter method from HandleReceivedPackage (code down below) then it process the data and if needed send the information it needs.

Here is the class on the server that handle all the different package:

using Server.Utilities;
using System.Net.Sockets;

namespace Server
{
    public static class HandleReceivedPacket
    {
        public static void Filter(TcpClient client, Stream stream, string data)
        {
            int code = int.Parse(data[1].ToString());
            string message = data.Substring(3);

            ServerLogger.Log($"Received data from client: [{code}]: {message}", LogLevel.Info);

            switch (code)
            {
                default:
                    Server.SendToClient(stream, PacketType.MESSAGE, "Message sent, but it's not a comand... Nothing happenned.");
                    break;
                case 0:
                    Server.SendToClient(stream, PacketType.TEST, "");
                    break;
                case 1:
                    Server.SendToClient(stream, PacketType.MESSAGE, "");
                    break;
                case 2:
                    Server.DisconnectClient(client);
                    break;
            }
        }
    }
}

Here is the class on the client that handle all the different package:

namespace ClientTest
{
    public static class HandleReceivedPacket
    {
        public enum PacketType
        {
            TEST = 0,
            MESSAGE = 1,
            DISCONNECT = 2
        }

        public static void Filter(string data)
        {
            int code = int.Parse(data[1].ToString());
            string message = data.Substring(3);

            switch (code)
            {
                default:
                    Console.WriteLine("Message sent, but it's not a comand... Nothing happenned.");
                    break;
                case 0:
                    Console.WriteLine("Connection: OK");
                    break;
                case 1:
                    Console.WriteLine("Your message have been received");
                    break;
                case 2:
                    Console.WriteLine("Disconnected !");
                    break;
            }
        }
    }
}

Conclusion:

So, with my actual method I could have 500 case in my switch (x2 since the server as to have the same) and my enum would be gigantic...

My question is:

Is there a better way of managing all these packets and how would you do it if you had to do it ?

Thanks in advance :)

Zartox29
  • 81
  • 8
  • `handlers[code](message);` – shingo Jun 09 '23 at 14:13
  • First of all I would go binary (`byte[]`) instead of strings .. it's more expensive to transmit and doing string parsing than directly operate with byte conversion ... then you could have an `enum` to define the message (if it is less than 256 different types it is basically a single `byte`) this way you can make your switch case - which imho is totally fine to use – derHugo Jun 09 '23 at 14:19
  • For a multiuser I wrote once I had a message protocol like `uint senderId, byte serviceID, byte message, byte[] content` .. where `service` and `message` are basically before mentioned single byte indices for selecting the handling service and message .. then within the message handler the handling method is responsible for converting the received `byte[]` into according type .. prefixed entire message length as prefix header and used `BitConverter` to extract expected types while moving forward the index ;) – derHugo Jun 09 '23 at 14:25
  • Yeah i'm already using byte[] to transmit but i convert it to string in another function before this one, sorry I should have mentionned it... But if i understand correctly you are converting once you know the code ? But i like this way it seems more straight forward :) I hoped for something else than the switch but i'll try your way, thanks ! – Zartox29 Jun 09 '23 at 14:42

0 Answers0