TCP-Based File Management System

Introduction

In today's digital landscape, seamless file management across remote systems is essential. Whether it's cloud storage, remote backups, or collaborative file sharing, robust and efficient data transfer is a necessity. In this blog, we’ll explore a custom TCP-based client-server architecture designed to handle file transfers, renaming, summary generation, and more—leveraging low-level networking with Python.

Understanding the Project Scope

The project consists of two key components:

The system is built using Python’s socket module, implementing a custom binary protocol for communication between the client and server. The primary functionalities include:

Now, let’s break down the technical details of each component.

Server Architecture: Handling Requests Efficiently

The server is the backbone of this system, running a TCP socket listener to accept incoming connections from clients. Upon receiving a request, the server deciphers the operation code (opcode) and processes the corresponding file operation.

Handling Client Requests

Each client request begins with a single-byte opcode that determines the operation type. The server extracts:

Based on the extracted opcode, the server executes one of the following handlers:

Handling File Uploads (PUT)

When a client sends a PUT request, the server:

def handle_put(client_socket, filename):
    file_size_bytes = client_socket.recv(4)
    file_size = int.from_bytes(file_size_bytes, 'big')
    
    with open(filename, 'wb') as file:
        bytes_read = 0
        while bytes_read < file_size:
            chunk = client_socket.recv(min(1024, file_size - bytes_read))
            file.write(chunk)
            bytes_read += len(chunk)

    send_success_response(client_socket)

Handling File Downloads (GET)

For a GET request, the server:

def handle_get(client_socket, filename):
    if not os.path.isfile(filename):
        send_error_response(client_socket, error_code=0b011)  # File Not Found
        return

    file_size = os.path.getsize(filename)
    response_header = (0b001 << 5 | len(filename)).to_bytes(1, 'big') + filename.encode() + file_size.to_bytes(4, 'big')
    
    client_socket.send(response_header)
    with open(filename, 'rb') as file:
        client_socket.sendfile(file)

Handling File Renaming (CHANGE)

For renaming files, the server:

def handle_change(client_socket, old_filename, new_filename):
    if os.path.exists(old_filename):
        os.rename(old_filename, new_filename)
        send_success_response(client_socket)
    else:
        send_error_response(client_socket, error_code=0b011)

Handling File Summaries (SUMMARY)

For text-based numerical files, the server can generate statistical summaries, including:

def handle_summary(client_socket, filename):
    try:
        with open(filename, 'r') as file:
            numbers = [float(line.strip()) for line in file if line.strip()]
        
        summary_content = f"Max: {max(numbers)}\nMin: {min(numbers)}\nAvg: {sum(numbers)/len(numbers)}\n"
        client_socket.send(summary_content.encode())
    except FileNotFoundError:
        send_error_response(client_socket, error_code=0b011)

Client Architecture: Sending Requests

The client program connects to the server and sends user-typed commands.

Sending a File (PUT)

def send_file(sock, filename):
    with open(filename, 'rb') as file:
        sock.sendall(file.read())

Receiving a File (GET)

def receive_file(sock, expected_filename):
    file_size = int.from_bytes(sock.recv(4), 'big')
    
    with open(expected_filename, 'wb') as file:
        while file_size > 0:
            chunk = sock.recv(min(1024, file_size))
            file.write(chunk)
            file_size -= len(chunk)

Requesting Help (HELP)

def send_help_request(sock):
    help_request_byte = 0b10000000
    sock.send(help_request_byte.to_bytes(1, 'big'))

Protocol Design: A Custom Binary Protocol

To optimize efficiency and reduce overhead, the system uses a custom binary protocol rather than plain text. Each message follows this structure:

Byte Description
1st Byte Opcode (3 bits) + Filename Length (5 bits)
Filename Variable Length (Max: 31 bytes)
File Size 4 Bytes (only for GET and PUT requests)
File Data Variable Length

This compact format ensures fast processing and reduced network bandwidth usage.

Download Project Files

Click the link below to download the complete TCP-based file management system source code.

Download TCP Project (tcp.zip)