Back to Projects

Multithreaded Chat Application

This was my Software Systems coursework at Imperial. I did it with one other person, Yichan Kim.

It's a UDP chat system in C. A multithreaded server on port 12000 keeps the user list and routes messages. Each client uses two threads: one reads the keyboard, one receives packets. Incoming chat is written to iChat_<PID>.txt so a second terminal can tail -f it. Clients send text of the form command$content. The server parses that, updates shared state under locks, and sends replies the same way.

The server is a listener thread that blocks in recvfrom, then a detached worker per datagram, plus a monitor thread. Identity is IP + port. The client list is a linked list behind a pthread_rwlock_t: read locks for broadcasts and lookups, write locks for add/remove, rename, kick. History is a circular buffer of the last 15 broadcasts with a mutex. Mute is per-client and one-way. Admin is whoever bound port 6666, and they can kick$ people.

Commands are the usual chat stuff: conn$, say$, sayto$, disconn$, mute/unmute, rename$. On join you get the last 15 broadcasts. The monitor runs every 30 seconds. Anyone idle for 5 minutes gets a ping$, and if they don't ret-ping$ within 10 seconds they're dropped. That path needed careful lock ordering, because the timeout holds the ping mutex then takes the client-list write lock, and other paths take the client list first.

A few things we didn't do. There's no CLI flag for admin, you have to bind 6666 by hand. The chat files aren't deleted on exit. UDP packets can just disappear, mute doesn't apply to private messages, and Error$ from the server isn't shown as the real message on the client.

Reflections

If I did it again I'd add a command-line flag for admin instead of hardcoding port 6666, delete the chat files on exit, and actually show the real Error$ text instead of a generic line. The run_chat.sh script also starts a second server, which is not what it's supposed to do.

The bit I'm still happy with is the command$content prefix. The client only displays whatever is after the first $, so user text never gets treated as a command. That plus the rwlock on the user list is most of why it didn't fall over when a few people were talking at once.

The lock ordering on the inactivity path was the annoying one. Get it wrong and you deadlock. Get it right and idle clients just quietly disappear.

CUDPpthreads