1

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 functions

  • game.c/.h → game logic

  • config.h → constants

When a new client connects, I need to:

  1. Ask the client for a username

  2. Validate it (check uniqueness)

  3. Create a player object

  4. Add it to the global player list

  5. 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?

  1. Inside server.c, meaning the server handles both networking and player initialization?

  2. Inside player.c, even though that mixes networking I/O with data structure logic?

  3. 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?

4
  • 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? Commented Nov 6 at 20:23
  • 1
    @freakish What is wrong with that? Writing game servers in C is my favorite. Commented 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. Commented Nov 7 at 6:25
  • Draw dependency graph and the answer will be clear. Commented Nov 7 at 10:18

2 Answers 2

1

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".

0

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)..

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.