Skip to main content
Harmanpreet Singh
All subjects

Coursework

Distributed Computing Systems

Client-server protocols, concurrency control, group communication and consistent hashing.

TCP servers, locks, multicast with persistence and a hash ring.

Project 1

Simple FTP client and server

A Java client and server that speak a small FTP-like protocol over TCP: get, put, delete, ls, cd, mkdir, pwd and quit.

Stack
  • Java
  • TCP sockets
  • Threads
Who and when
Pair project with Tejas D. Shinde, as the repository's README states, January to February 2025
My contribution
We wrote the client and the threaded server together.

Working demo

Run an FTP session

Runs in your browser

Try this: Type ls, then get notes.txt, then put your own local file, and read the trace beside the terminal.

A simulation of the protocol with virtual files, not a real network session.

Loading demo...

What the original did

  • The server listens on a port, accepts clients and handles each on its own thread, starting in the directory the server runs from.
  • Commands travel as UTF strings. For get, the server replies OK and the file length, then the bytes. For put, the client sends the length, then the bytes.
  • Errors such as a missing file or directory are returned as ERROR messages.

How it works

  • Sending the length before the bytes lets the receiver know exactly when the file ends on a stream socket.
  • A thread per client means one slow transfer does not block other clients.
  • Each client connection keeps its own current directory.

Added for this showcase

  • A virtual file system on each side and a terminal that accepts the real command set.
  • A live protocol trace showing the exact messages exchanged for each command.

Notes

  • The demo simulates both sides in the browser. No sockets are opened and no real files are touched.

Project 2

Concurrent FTP with locking and terminate

The FTP server extended with background transfers, a read-write lock per file so readers can overlap but a writer is exclusive, and a terminate command on a second port.

Stack
  • Java
  • TCP sockets
  • ReadWriteLock
  • Threads
Who and when
Pair project with Tejas D. Shinde, from the repository history, February 2025
My contribution
We built the locking, the background transfers and the terminate path together.

Working demo

Run concurrent transfers

Runs in your browser

Try this: Load the 'two readers and a writer' scenario and see the writer wait, then terminate the long reader.

A discrete-event simulation of the lock rules, not a real server.

Loading demo...

What the original did

  • The server listens on two ports: one for commands and one for terminate requests.
  • A trailing & runs get or put in the background, and each command gets an ID.
  • get takes a read lock on the file and put takes a write lock, so several readers can run together but a writer waits for everyone.
  • terminate <id> sets a flag that the transfer checks every 1000 bytes, then stops and a partly written upload is removed.

How it works

  • Locks are kept per file name in a concurrent map, so unrelated files never wait on each other.
  • A separate terminate port means a stop request is not stuck behind the command it wants to stop.
  • Checking the flag between chunks makes a stop quick without needing to interrupt a blocking socket call.

Added for this showcase

  • A timeline with one lane per command showing waiting, transferring, finished and terminated.
  • A lock inspector for the shared file, and ready-made scenarios for readers, a writer and a terminate.

Notes

  • The timeline simulates the locking rules on a virtual clock. It models the lock behaviour, not Java's thread scheduling.

Project 3

Persistent multicast with a coordinator

A coordinator and several participants: participants register, disconnect and reconnect, and the coordinator keeps messages for a time threshold so those who were offline can still receive them.

Stack
  • Java
  • TCP sockets
  • Threads
Who and when
Individual project, from the repository history, March 2025
My contribution
I wrote the coordinator and the participant.

Working demo

Run a multicast group

Runs in your browser

Try this: Disconnect P2, send two messages, advance the clock past td, then reconnect P2.

A simulation of the coordinator's rules with a virtual clock, not a networked system.

Loading demo...

What the original did

  • Participants send register, deregister, disconnect, reconnect and msend commands to the coordinator.
  • A message goes to everyone registered when it was sent. Online participants receive it immediately.
  • The coordinator keeps each message for td seconds. When a participant registers or reconnects, it sends any kept message still inside the window that the participant was a recipient of.
  • Each participant appends what it receives to its own log file.

How it works

  • The set of recipients is fixed at send time, so someone who joins later does not receive older messages.
  • Persistence is a time window, not a delivery guarantee: a message older than td is gone.
  • Because the coordinator does not remember what it already delivered, it can send a kept message again on a later reconnect.

Added for this showcase

  • Cards for the coordinator and three participants with the real command set, and a clock you can advance.
  • A message history showing recipients, who has received what, and when each message expires.
  • A switch between my original behaviour and a version that delivers each message at most once.

Notes

  • Looking at the code again for the demo, I saw that a reconnecting participant can receive a message it already got, and that the participant does not filter repeats. The demo shows this in the original mode and fixes it in the other.

Project 4

Distributed key-value service on a hash ring

A bootstrap server and name servers share a ring of 1024 key positions. Servers enter and exit, key ranges move with them, and lookups, inserts and deletes are routed to the owner.

Stack
  • Java
  • TCP sockets
  • Consistent hashing
  • Threads
Who and when
Individual project, from the repository history, March to April 2025
My contribution
I wrote the bootstrap server and the name server.

Working demo

Join, exit and look up

Runs in your browser

Try this: Enter servers 434 and 650 and look up key 500. Then exit 434 and look up key 109, once with my original code and once with the corrected version.

The ring logic runs in your browser with no network. It follows the rules of my Java code.

Loading demo...

What the original did

  • The bootstrap server has id 0, loads its initial key-value pairs from a config file and keeps the map of ring members.
  • A key belongs to the first server at or after it on the ring, wrapping around past 1023.
  • A name server joins by asking the bootstrap server, which hands over the pairs it holds in the new server's range (predecessor, id] and returns the predecessor and successor.
  • A name server exits by sending all its pairs to the successor it was given, then telling the bootstrap server it left.
  • lookup, insert and delete go through the bootstrap server, which forwards them to the owner and reports the path taken.

How it works

  • Ownership is a range on a circle, so a join or exit only moves one range.
  • The bootstrap server is the only place that knows the whole ring.
  • Pairs live in memory and are seeded from the config file. This is not persistent storage.

Added for this showcase

  • The ring drawn with every key on it, animated key movement on join and exit, and the path of each request.
  • The original config as a starting point, with the 35 fruit and vegetable keys.
  • A switch that reproduces a stale-successor problem I found, and the corrected handover.

Notes

  • Rereading the code for this demo I found two problems. First, a join only takes keys from the bootstrap server's own map, so a server that joins in front of another name server never receives the keys that server holds, and lookups for them fail. Second, a name server remembers the successor it had when it joined and never updates it, so if it exits after another server joined in between, it hands its keys to the wrong node.
  • The demo runs both my original rules and a corrected version, and the unit tests check each: the corrected ring keeps every key reachable over hundreds of random joins and exits.
  • There is no replication, and the bootstrap server is a single point of failure. This is a coursework design, not a fault-tolerant system.

Read the earlier write-up of this project