The project implements a remote file service where clients can:
- Upload files to the server (
WRITE) - Download files from the server (
GET) - Delete files from the server (
RM)
It also includes a concurrency stress-test driver to validate correctness under randomized, parallel workloads.
.
├── client/ # Client-side executable output
│ ├── backup/ # Backup files for reset rule
│ └── rfs # Compiled client executable
├── server/ # Server-side executable output
│ ├── backup/ # Backup files for reset rule
│ └── server # Compiled server executable
├── src/
│ ├── client/client.c # Client implementation
│ ├── server/server.c # Server implementation
│ ├── messenger.c # Message passing and file transfer
│ ├── queue.c # Generic circular queue
│ ├── waitingroom.c # Threaded waiting room for requests
│ └── concurrency_driver.c # Stress-test driver
├── include/ # Header files
├── build/ # Compiled object files
├── Makefile # Build automation
└── README.md # This file
The client program (rfs) issues commands to the server:
- WRITE: Uploads a local file to the server.
- GET: Downloads a file from the server.
- RM: Removes a file from the server.
Key aspects:
- Implements a handshake protocol (
GO→CONTINUE) to ensure synchronization before file transfer. - Provides detailed error handling (
handle_error) that logs, informs the server, and cleans up resources. - Encapsulates command-specific logic:
handle_write()→ sends a file and waits for server acknowledgment.handle_get()→ receives a file and confirms success.handle_rm()→ receives server confirmation of deletion.
- Demonstrates socket lifecycle management: connect → transact → close.
The server program (server/server) listens for client connections and executes commands.
Key aspects:
- Uses
accept()to handle multiple incoming client sockets. - Delegates requests to the waiting room (threaded request queue).
- Command handlers:
handle_write()→ receives a file and saves it to disk.handle_get()→ sends a file to the client and waits for confirmation.handle_rm()→ deletes a file and responds with success/failure.
- Gracefully shuts down on
SIGINT(Ctrl+C), cleaning up sockets and threads. - Validates handshake messages (
GO,CONTINUE) before acting.
This file demonstrates robust server-side socket programming and safe multi-threading.
This module abstracts low-level TCP communication:
send_msg/receive_msg: Reliable string-based messaging.send_file/receive_file: File transfer with progress bar output.- Uses
stat,fread,fwrite, and system calls to validate directories and write safely. - Implements dynamic memory management (
malloc,realloc,free) with safety macros. - Features I/O multiplexing concepts (ensures synchronization between sender/receiver).
This file demonstrates buffer management, robust error handling, and system-level I/O.
Implements a generic circular doubly-linked queue:
push()→ enqueue new requests.pop()→ dequeue requests in FIFO order.remove_node()→ arbitrary removal with pointer repair.destroy_queue()→ free all resources.
This queue underpins the waiting room, making it possible to process per-file request queues safely.
The waiting room coordinates multi-threaded request handling:
- Maps each file to a dedicated worker thread (
file_handler_t). - Each worker thread:
- Waits on a condition variable.
- Processes requests sequentially (preserves per-file ordering).
- Terminates when no requests remain.
- Uses
pthread_mutex_tandpthread_cond_tfor safe synchronization. make_request()ensures new threads are created when a file is first accessed.
This demonstrates concurrency control, thread lifecycle management, and fine-grained synchronization in C.
The stress test driver validates concurrency under load:
- Spawns child processes that randomly issue
WRITE,GET, andRMrequests against the server. - Builds randomized filenames and command arguments.
- Uses
fork()andexecvp()to run therfsclient many times in parallel. - Ensures the server handles interleaved workloads safely without race conditions or data corruption.
This file highlights process control, randomized testing, and robustness under concurrency.
sequenceDiagram
participant C as Client (rfs)
participant M as Messenger (TCP wrappers)
participant S as Server
Note over C,S: Example: Client wants to SEND a file
C->>M: open socket to server (connect)
M->>S: establish TCP connection
S-->>M: accept connection
C->>M: send operation type (e.g., "SEND")
M->>S: transmit command string
S-->>M: acknowledge operation
C->>M: send metadata<br/>(filename, size)
M->>S: transmit metadata
S-->>M: directory check result (int)
alt directory OK
C->>M: stream file data (chunks)
loop until EOF
M->>S: send file block
S-->>M: acknowledge block
end
S-->>M: final confirmation
M-->>C: report success
else directory missing / error
S-->>M: send error code
M-->>C: report failure
end
Note over C,S: Other operations (GET, RM) follow the same<br/>pattern: command → metadata → data stream → confirmation
This project is managed by a Makefile. Key features:
-
Compiler flags:
-Wall -Wextra→ strict warnings.-g→ debugging symbols.-Iinclude→ include path for headers.-MMD -MP→ auto-generate dependency files.
-
Targets:
make all→ builds client, server, and driver.make clean→ removes compiled artifacts and executables.make reset→ restoresclient/andserver/directories to backup state.
-
Executables:
client/rfs→ Client program.server/server→ Server program.concurrency_driver→ Stress test tool.
-
Debug mode:
make DEBUG=1Compiles with -DEBUG for additional logging.
./server/serverThe server will bind to a TCP port and wait for clients.
Upload a file to the server.
./client/rfs WRITE local.txt remote.txtlocal.txt: File on client machine.remote.txt: Target name on server.
Download a file from the server.
./client/rfs GET remote.txt local_copy.txtremote.txt: File on server.local_copy.txt: Destination on client.
Delete a file from the server.
./client/rfs RM remote.txtRun randomized concurrent requests:
./concurrency_driverThis will spawn many clients simultaneously, issuing random WRITE, GET, and RM commands.
This project demonstrates:
- Networking: TCP sockets,
bind,listen,accept,connect. - Concurrency: POSIX threads, mutexes, condition variables.
- Processes:
fork,execvp, randomized stress testing. - Memory Management: Safe dynamic allocation, cleanup, buffer management.
- File I/O:
fread,fwrite,stat,unlink, robust error handling. - Synchronization Protocols: Custom two-phase handshake (
GO/CONTINUE) for reliability. - Build Automation: Complex Makefile with dependency generation, directory structuring, and debug support.
MIT License — free to use, modify, and share.