3
\$\begingroup\$

I've been wondering a lot lately about how to make an optimised server structuration, and i came to the conclusion that i severely lack knowledge on the subject.

I'll be doing this with either C, C++ or C#, with a preference for the latter.

Context:

I have a server that can operate more than 3K clients at one time.

This server is a game server, hence it only receives key inputs from the clients, for security measures.

Therefore the server is doing every operation on the user's data, and send back enough information to the client in order to display a personal GUI. (The server is of course a console application, don't get me wrong.)

Approaches:

1- 1 Client = 1 Logic Thread

(The thread does the player calculation)

Pros: every client runs his own server code, the server is more responsive to a particular client's request.

Cons: I do not have the insurance that a particular client will iterate its code 14 times while another would have iterated it 10, (so the two players, side by side, if it was for a movement operation, can become 4 squares afar, which should not be the case, as every player should move at an exact same speed)

Locking every thread to perform actions until a next logic loop happens can be quite devastating if something bad happens on any of the client, leading to severe lags in worst cases.

2- 1 Client = 1 Entry Thread, Main logic loop

(The thread receives the keys pressed by its client)

Pros: As the logic is all in the same loop, there is no desynchronization problems anymore.

Cons: Iterating ALL the game logic in one loop will most probably cause severe latency if the operations becomes advanced.

Moreover, if many clients are to catch up with all the current data being processed (sudden peak of connections), it would also cause additional latency, a partial solution would be to retrieve those datas in the Entry Thread.

3- 1 Client = 1 Entry Thread, X Logic threads, 1 Logic Thread synchronizer

(Entry thread receives keys, register the client in the concerned threads (One for each kind of action (Moving, Acquiring user data, Battle, Etc...)), Those threads gives the information whenever they can, and the Logic thread synchronizer ensures that tasks that needs to be "Ordered" in time are ordered.)

Pros: Share computation resources among all the Logic Threads, ensuring minimum latency for clients.

Cons: High vulnerability to resources concurrency, and if a particular task is done faster than another task that is to be synchronized with it, becomes as slow as the latter.

Question:

As i said earlier, i certainly lack knowledge about networking, threading, and concurrency, to efficiently order the structure of my program. Therefore, I'm asking it here:

What would be the best approach to take, and how should the global skeleton should be ordered to minimize latency, and permits a large number of synchronous users to play on the server.

Additional information

Maybe a bit of information about the idea behind this all will help.

My goal here is to create a server that will be used to run a simple RPG, which needs to have movement synchronization on the map (old school square-to-square movements), turn by turn instanciated battle (e.g. Dragon Quest, Final Fantasy, Pokemon), and exchange of user data (seeing X's profile, see how many monsters he killed, his guild, etc.)

If i'm asking for more than 3K clients at the same time, it is because i do not want to make a pile of junk that holds in place by a miracle. I want to further my knowledge on networking and its applied logic, would it be programmative logic or structuration logic.

So basically the problem is "Having a maximum of clients, on a minimally powerful server, therefore optimizing it as much as possible."

\$\endgroup\$
  • \$\begingroup\$ I think the general approach is to have non-blocking threads for the client input, and a thread for the rest. \$\endgroup\$ – Vaillancourt Dec 9 '16 at 17:29
  • 1
    \$\begingroup\$ You could get inspired by the Source Multiplayer Networking article. \$\endgroup\$ – Vaillancourt Dec 9 '16 at 17:30
  • 1
    \$\begingroup\$ No, unfortunately, I don't have info on that. However, you could take a look at this book. I'm not sure it covers distributive servers. \$\endgroup\$ – Vaillancourt Dec 12 '16 at 12:18
  • 1
    \$\begingroup\$ There is also an upcoming book that was kickstarted. It's not released yet. \$\endgroup\$ – Vaillancourt Dec 12 '16 at 12:18
  • 1
    \$\begingroup\$ You need IOCP it uses in\out completion ports to spawn kernel threads that are much more light weight and faster then normal threads. there is a really good .Net 3.5 sample that is still very relevant to this day. I did lots of tests with this and build a very cool server that could handle 300K clients all spaming 100kb every 4ms, infact this is what got me in to game dev as I needed something to test my server. This was all in a controlled LAN setup so thing will be different over the net \$\endgroup\$ – Justin William Stanley Bryant Feb 28 '17 at 4:59
1
\$\begingroup\$

Don't have a thread for each client - you'll be shooting yourself in the foot by thrashing the CPU cache more as more players connect. If you're not looking to run multiple server processes per machine, then you'd ideally want your number of threads to match your number of cores to reduce context switching. One thread should be enough to read in input packets for all connected players and update data structures for the logic thread(s) to operate on.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.