Distributed Chat Server with Java NIO
Build a chat server in Java with NIO (non-blocking I/O): instead of one thread per user, a single thread watches every connection with a Selector and handles whichever ones are ready to read or write, so one server can serve thousands of clients. Users connect with a terminal client (or netcat), pick a name, join rooms and chat, with messages delivered only to the people in the same room. You'll handle the tricky parts of non-blocking networking yourself: messages that arrive in pieces, writes that can't be sent all at once, and clients that disconnect suddenly or read too slowly. You'll learn channels, buffers and selectors, designing a text protocol, managing per-connection state, backpressure, and load testing your own server.
- Estimate
- ~13h
- Steps
- 7
- Completed by
- 0
- Proposed by
- codeseed.app
Java NIO · Selectors · Sockets
Project roadmap
- 01
Set up the selector loop
~2hCreate a ServerSocketChannel in non-blocking mode, register it with a Selector for accept events, and write the event loop: select, go through the ready keys, and handle accept (registering the new client's SocketChannel for reads, with a per-client state object attached to its key). Done when: several netcat clients can connect, and the server logs each connection.
- 02
Read and write with buffers
~2.5hGive each client a read ByteBuffer and a queue of outgoing buffers. On a read event, read into the buffer, split it into complete lines (keeping any partial line for the next read), and decode them as UTF-8. To send, add to the client's queue and register interest in write events; on a write event, write as much as possible and remove interest in writes when the queue is empty. Done when: an echo test works, even for long messages sent in several pieces.
- 03
Define the chat protocol
~1.5hDefine text commands: /nick NAME (required first, unique, and 2 to 20 allowed characters), /join ROOM, /leave, /rooms (list rooms with their number of users), /who (users in the current room), /quit, and plain lines as messages. Parse them into commands with clear error replies for invalid input, and limit line length. Done when: every command works from netcat, and invalid ones get clear errors.
- 04
Route messages to rooms
~1.5hKeep a map of rooms to their clients, send each message to everyone else in the sender's room with the sender's name and time, announce joins and leaves, and remove empty rooms. Done when: messages reach only the people in the same room.
- 05
Handle edge cases
~2hHandle clients that disconnect (read returns -1 or an IOException) by cancelling their key, closing the channel and announcing that they left. Protect against slow clients: if a client's outgoing queue grows past a limit, disconnect it instead of using unlimited memory. Close idle clients after a timeout. Shut down cleanly on Ctrl+C. Done when: sudden disconnects and slow clients never affect the server or other clients.
- 06
Write a client and load test
~2hWrite a simple terminal client (with one thread reading the keyboard and one reading the server), and a load test program (run only against your own server) that opens thousands of connections spread across rooms, sends messages at a steady rate, and measures delivery time. Record the connections, messages per second and latency in README.md. Done when: the server handles thousands of clients on one thread, and README.md shows the results.
- 07
Test it
~1.5hWrite JUnit tests that start the server on a free port and connect real client sockets: nicknames, rooms, message routing, partial lines, disconnects and slow client handling. Test the protocol parsing separately. Done when: all tests pass.
Resources
Ready to build this?
Get a GitHub repo and start building. Your AI reviewer checks each step as you go.
Tech stack