Multi-threaded Chat Server over TCP
Build a chat server in Rust using only the standard library: raw TCP sockets and one thread per connected user. People connect with a terminal client (or netcat), choose a username, and every message they type is sent to everyone else. The server announces who joins and leaves, supports a few commands such as /list and /nick, and keeps working when a client disconnects suddenly. You'll learn std::net TCP sockets, threads, sharing state safely between threads with Arc and Mutex, channels (mpsc), and how Rust's ownership rules prevent data races at compile time.
- Estimate
- ~10h
- Steps
- 6
- Completed by
- 0
- Proposed by
- codeseed.app
std::net
Project roadmap
- 01
Accept connections
~1.5hCreate a Cargo project. Bind a TcpListener to 127.0.0.1:7878 (configurable by an argument), and for each incoming connection spawn a thread that greets the client and echoes back what it sends, reading lines with BufReader. Done when: two netcat sessions can connect at once, and each gets its own lines echoed back.
- 02
Ask for a username
~1.5hWhen a client connects, ask for a username and check it: 1 to 20 letters, digits or underscores, and not already taken. Keep the connected users in shared state, Arc<Mutex<HashMap<String, ...>>>. Ask again when the name is invalid or taken. Done when: two clients can't use the same name, and invalid names are rejected.
- 03
Broadcast messages
~2hGive each client an mpsc channel and a dedicated writer thread that sends everything it receives from the channel to the socket. Store each client's Sender in the shared map. When a client types a line, send it as [name] message to every other client's channel. Keep the lock only while copying the list of senders, not while writing. Done when: a message typed in one client appears in all the others.
- 04
Handle joins, leaves and commands
~2hAnnounce *** name joined and *** name left to everyone. Detect disconnects (reading returns 0 bytes or an error) and remove the user from the map. Add commands: /list (who's online), /nick newname and /quit. Limit the length of messages, for example 500 characters. Done when: closing a client announces that it left, and the commands work.
- 05
Write the terminal client
~1.5hAdd a second binary, a client that connects to the server and uses two threads: one reads the keyboard and sends lines, the other prints what arrives from the server. Exit cleanly when the server closes the connection. Done when: several clients can chat with each other in separate terminals.
- 06
Test it
~1.5hMove the logic (validating usernames, parsing commands, formatting messages) into functions with unit tests. Add an integration test that starts the server on a free port, connects two clients from the test, and checks that a message from one reaches the other. Done when: cargo test passes, and cargo clippy reports no warnings.
Ready to build this?
Get a GitHub repo and start building. Your AI reviewer checks each step as you go.
Tech stack