I’m writing a multiplayer server in C using sockets and pthreads. The project is separated by responsibility:
server.c/.h→ networking (socket, bind, listen, accept, thread creation)player.c/.h→ player data structure and functionsgame.c/.h→ game logicconfig.h→ constants
When a new client connects, I need to:
Ask the client for a username
Validate it (check uniqueness)
Create a player object
Add it to the global player list
Then move the client into the lobby/menu loop
Right now this logic is inside a function like handle_client(...), which is called after accept().
Where should this function belong?
Inside
server.c, meaning the server handles both networking and player initialization?Inside
player.c, even though that mixes networking I/O with data structure logic?Or should I create a new module, e.g.,
controller.c, where the server only accepts sockets and the controller handles client interaction flow?
I want to maintain clean separation of responsibilities. Which design makes more sense?
-
The cleanest way is to create a new module. But dear God, are you really going to write a game server in C? Do you like pain? Or is this some school project?freakish– freakish2025年11月06日 20:23:54 +00:00Commented Nov 6 at 20:23
-
1@freakish What is wrong with that? Writing game servers in C is my favorite.CPlus– CPlus ♦2025年11月07日 05:58:39 +00:00Commented Nov 7 at 5:58
-
1@CPlus I didn't say it is wrong. Only that is painful. There are plenty modern languages that can do the job done, and are like 20x easier and faster to code. Especially, why would you want to deal with so low level details like sockets? And where's encryption? Authentication? Where's all of that? Without that this must be school project. With, it is just soooo much work.freakish– freakish2025年11月07日 06:25:50 +00:00Commented Nov 7 at 6:25
-
Draw dependency graph and the answer will be clear.Basilevs– Basilevs2025年11月07日 10:18:19 +00:00Commented Nov 7 at 10:18
2 Answers 2
Whenever one has a requirement which does not fit into the existing module structure of a system, I would recommend to start with a new module first.
Said that, during the evolution of this new module, the development of the functionality may produce requirements which cause the necessity to change, extend and evolve existing modules. So when you develop your new connection module, you should consider if some of the steps like username validation or player creation should really stay in the controller, or if they better fit into the existing player, game logic or server module (for example as service functions, called by the new controller).
In the end, the resulting system may look differently as you expected it to look like at the beginning. Maybe the necessity for the new controller vanishes. Maybe the responsibilities of the controller change and it needs a more descriptive name. Maybe you end up with one or more controllers and additional service modules. But this is best decided by constantly implementing and refactoring the system, not by being too focussed on a structure recommended by some random people from the internet.
Or, to quote von Moltke: "no plan survives contact with the enemy".
The logic that you describe looks very much like session management, the glue that ties together network connection with a user.
As it is a different concern than the ones handled in other modules, create a new module. Otherwise you'll end up with lots of interdependencies scattered around and maintenance nightmares:
- server manages the connection and communication with devices
- session links a network connection with the a player. It manages the authentication and the list of active users (e.g. when a user actively disconnects or becomes inactive for a longer time, to close session and remove user from the global list).
- player manages player account info and player data structures
Isolating sessions management from the network logic and the game logic facilitates abstracting from the raw network layer. For example, you could allow users to reconnect if the connection is lost (e.g. a when a mobile user leaves wifi and switches to carrier data with another network address/interface) without losing game state.
WHere the user input and output is managed is up to you and depends on some other architectural decisions (e.g. MVC, MVP or MVVM + do all users use a client application or is it a P2P application)..
Explore related questions
See similar questions with these tags.