I started with thread-per-connection because it's the obvious answer, but they pushed back pretty fast on what happens at 10k clients.
Start by clarifying requirements and scale, then propose a thread-per-connection model with a shared client registry and broadcast queue, explaining how it handles joins/leaves. Detail message framing with length-prefixed messages and a clean shutdown sequence using a shutdown flag and socket closure.
Pro tip: Mention that you'd use a write queue per client to avoid blocking the broadcast loop on slow consumers, and that you'd test with abrupt disconnects to ensure the server doesn't crash.
Ask about expected number of concurrent clients, message size, and whether ordering or delivery guarantees are needed. This informs the concurrency model and framing choices.
Propose a thread-per-connection model for simplicity, or an event-driven model (e.g., epoll) for high scalability. Explain how a shared data structure (e.g., concurrent set) tracks active clients and synchronizes broadcasts.
Use length-prefixed framing: a fixed-size header (e.g., 4-byte big-endian length) followed by the payload. This handles TCP stream boundaries and allows the server to read complete messages.
On join, add the client to the registry; on leave (detected by read returning 0 or an error), remove it and close the socket. Broadcast by iterating over a snapshot of the registry and enqueuing messages to each client's write queue.
Use a shutdown flag and close the listening socket to stop accepting new connections. Signal all client threads to exit, drain write queues, and join threads before exiting the process.
AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.