From-Scratch Build · Programming · C
No framework, no library doing the hard part — just C, sockets, and the operating system. terminalChat is a real-time chat client and server where many people type in their terminals and see each other's messages instantly. I rebuilt it from scratch because writing a networked program in C is where the abstractions fall away and you finally see how machines actually talk.
What it is
In a high-level language, "send a message" is one line. In C, you confront everything underneath it: open a socket, bind it, listen, accept connections, read bytes into a buffer, handle a client that disconnects mid-sentence, and broadcast to everyone else — all while managing memory yourself. terminalChat is a server that juggles many simultaneous clients and the small client that talks to it.
The crux is handling many connections at once without threads spiralling out of control. A single loop watching all sockets with select() — ready to read from whichever client speaks next — is the classic, elegant answer, and building it teaches the foundation every network server is built on.
The stack
Close to the metal — the OS primitives, used directly.
Reliable, ordered byte streams between client and server — the foundation of the chat.
Listen for and accept new client connections as they arrive.
Watch every client socket in one loop and react to whichever has data ready.
Relay each incoming message to all other connected clients.
Read into and manage byte buffers by hand — no garbage collector to lean on.
Detect dropped clients cleanly and free their resources without crashing the server.
Architecture
The server runs one loop that never blocks on a single client:
The server opens a socket and waits for connections.
Each new client is added to the set of watched sockets.
select() reports which sockets have data ready to read.
The server reads the message from whichever client sent it.
It relays that message to every other connected client.
The real thing
This is the actual end-to-end smoke test: it starts the C server, connects two separate client processes, and one client (bob) receives the message the other (alice) sends. The transcript below is bob's real terminal output — captured, not mocked.
* welcome to TerminalChat — type your nickname: * you are now known as bob * alice joined the chat alice: hello from alice * alice left the chat
The program is real C. Build it with make (or one gcc line), run the server, and point clients at it:
# build everything (server, client, framing test) $ make # terminal 1 — start the server $ ./bin/server 5050 # terminal 2 — join the chat $ ./bin/client 127.0.0.1 5050
It's portable: the same source builds on Windows (Winsock2, linked with -lws2_32) and on Linux/macOS (POSIX sockets), guarded by #ifdef _WIN32. A unit test on the message-framing functions reports all 23 assertions passed.
Reflection
select() loop handles many clients elegantly — the model behind the fastest servers.