Skip to main content

File Transfer Protocol (FTP)

FTP Protocol Overview

The File Transfer Protocol (FTP) is a standard network protocol used to transfer files from one host to another over a TCP-based network, such as the Internet. It operates using a client-server architecture. The client requests files or uploads them, while the server responds to these requests. FTP typically uses two channels:

  1. Control Connection: To send commands and receive responses.
  2. Data Connection: To transfer the actual file data.

Simulation of a Simple File Transfer in C using Sockets

Below is an example of a simple simulation of a file transfer protocol where:

  1. The client requests a file by its name.
  2. The server checks if the file exists and sends its content back to the client.

Server Code

The server listens for incoming connections, receives a file request, reads the file, and sends its content to the client

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 8080
#define BUFFER_SIZE 1024

void handle_client(int client_socket) {
char buffer[BUFFER_SIZE] = {0};
char filename[BUFFER_SIZE] = {0};

// Receive filename from client

int bytes_received = recv(client_socket, filename, BUFFER_SIZE, 0);
if (bytes_received < 0) {
perror("Error receiving filename");
close(client_socket);
return;
}

// Open the requested file

FILE *file = fopen(filename, "r");
if (file == NULL) {
char *error_message = "File not found";
send(client_socket, error_message, strlen(error_message), 0);
perror("File not found");
} else {

// Read file and send its content

while (fgets(buffer, BUFFER_SIZE, file) != NULL) {
send(client_socket, buffer, strlen(buffer), 0);
memset(buffer, 0, BUFFER_SIZE);
}

printf("File Send to client\n");
fclose(file);
}
close(client_socket);
}

int main() {

int server_socket, client_socket;
struct sockaddr_in server_addr, client_addr;
socklen_t addr_len = sizeof(client_addr);

// Create server socket

server_socket = socket(AF_INET, SOCK_STREAM, 0);
if (server_socket == 0) {
perror("Socket failed");
exit(EXIT_FAILURE);
}

// Configure server address
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(PORT);

// Bind socket to address
if (bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("Bind failed");
exit(EXIT_FAILURE);
}

// Start listening
if (listen(server_socket, 3) < 0) {
perror("Listen failed");
exit(EXIT_FAILURE);
}

printf("Server is listening on port %d\n", PORT);
while (1) {
// Accept client connection
client_socket = accept(server_socket, (struct sockaddr *)&client_addr, &addr_len);
if (client_socket < 0) {
perror("Accept failed");
exit(EXIT_FAILURE);
}

printf("Client connected\n");
// Handle client

handle_client(client_socket);
}

close(server_socket);
return 0;
}

Client Code

The client connects to the server, sends the file name, and displays the received file content.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 8080
#define BUFFER_SIZE 1024

int main() {
int client_socket;
struct sockaddr_in server_addr;
char buffer[BUFFER_SIZE] = {0};
char filename[BUFFER_SIZE] = {0};

// Create client socket

client_socket = socket(AF_INET, SOCK_STREAM, 0);
if (client_socket < 0) {
    perror("Socket creation failed");
    exit(EXIT_FAILURE);
    }

// Configure server address

server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");

// Connect to server
if (connect(client_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("Connection failed");
exit(EXIT_FAILURE);

}
// Get filename from user
printf("Enter the filename to request: ");
scanf("%s", filename);

// Send filename to server
send(client_socket, filename, strlen(filename), 0);

// Receive and print file content

printf("File content received:\n");
while (recv(client_socket, buffer, BUFFER_SIZE, 0) > 0) {
printf("%s", buffer);
memset(buffer, 0, BUFFER_SIZE);
}

printf("\n");
close(client_socket);

return 0;
}

How to Run

  1. Save the server code in a file, e.g., server.c, and compile it:


    gcc server.c -o server
  2. Save the client code in a file, e.g., client.c, and compile it:


    gcc client.c -o client
  3. Run the server in one terminal:


    ./server
  4. Run the client in another terminal:


    ./client
  5. Enter the name of a file available in the server's directory. If the file exists, the client will receive and display its content.

This simulation demonstrates the basic principles of an FTP-like file transfer. For real-world FTP implementations, authentication, error handling, and additional features are required.

Code Explanation

Server Code

The server is designed to:

  1. Listen for client connections.
  2. Receive a file request from the client.
  3. Send the file's content back to the client if it exists.

  1. Include Headers:


    #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h>

    These headers provide necessary functions for I/O operations, socket programming, and memory handling.

  2. Constants:


    #define PORT 8080 #define BUFFER_SIZE 1024
    • PORT: The server listens on port 8080. This can be changed as needed.
    • BUFFER_SIZE: Sets the size of the buffer for file reading and sending data.
  3. handle_client Function:
    This function processes each client request.


    void handle_client(int client_socket) { char buffer[BUFFER_SIZE] = {0}; char filename[BUFFER_SIZE] = {0};
    • filename: Stores the name of the requested file.

    • buffer: Temporary storage for reading file content.

    • Receive Filename:


      int bytes_received = recv(client_socket, filename, BUFFER_SIZE, 0);

      recv receives the filename from the client. If bytes_received is negative, an error occurred.

    • Check and Open the File:


      FILE *file = fopen(filename, "r"); if (file == NULL) { char *error_message = "File not found"; send(client_socket, error_message, strlen(error_message), 0); perror("File not found"); }

      If the file doesn't exist, an error message is sent back to the client.

    • Read and Send File Content:


      while (fgets(buffer, BUFFER_SIZE, file) != NULL) { send(client_socket, buffer, strlen(buffer), 0); memset(buffer, 0, BUFFER_SIZE); } fclose(file);
      • fgets reads a line from the file.
      • send sends the content line-by-line to the client.
      • memset clears the buffer after each send.
    • Close Connection:


      close(client_socket);
  4. Main Function:

    • Create Socket:


      server_socket = socket(AF_INET, SOCK_STREAM, 0);

      Creates a TCP socket.

    • Bind Socket to Address:


      bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr));

      Binds the socket to PORT and INADDR_ANY (all available interfaces).

    • Start Listening:


      listen(server_socket, 3);

      Listens for incoming connections. The 3 specifies the maximum queue length for pending connections.

    • Accept Connections in a Loop:

      ]
      client_socket = accept(server_socket, (struct sockaddr *)&client_addr, &addr_len); handle_client(client_socket);
      • accept waits for a client to connect.
      • handle_client is called to process the client request.

Client Code

The client is designed to:

  1. Connect to the server.
  2. Send the name of the requested file.
  3. Receive and display the file content.

  1. Include Headers:
    Similar to the server code.

  2. Constants:
    Same as the server code.

  3. Main Function:

    • Create Socket:


      client_socket = socket(AF_INET, SOCK_STREAM, 0);

      Creates a TCP socket.

    • Configure Server Address:


      server_addr.sin_family = AF_INET; server_addr.sin_port = htons(PORT); server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");

      Specifies the server's IP (127.0.0.1 for localhost) and port.

    • Connect to Server:


      connect(client_socket, (struct sockaddr *)&server_addr, sizeof(server_addr));

      Initiates a connection to the server.

    • Send Filename:


      send(client_socket, filename, strlen(filename), 0);

      Sends the name of the requested file to the server.

    • Receive and Print File Content:


      while (recv(client_socket, buffer, BUFFER_SIZE, 0) > 0) { printf("%s", buffer); memset(buffer, 0, BUFFER_SIZE); }
      • recv receives file content from the server.
      • printf displays the received content.
    • Close Socket:


      close(client_socket);

Key Points:

  1. Error Handling:

    • Server handles cases where the file is not found.
    • Proper error messages are displayed on both server and client.
  2. Buffered Transfer:
    Data is read and sent in chunks (BUFFER_SIZE).

  3. Client-Server Communication:

    • Client sends a filename.
    • Server responds with either the file content or an error message.
  4. Multithreading (Optional):
    The server can be extended to handle multiple clients using threads or fork.

This simple simulation demonstrates the basic workflow of file transfer using sockets in C.

Comments

Popular posts from this blog

Server/Client Communication-python

The basic mechanisms of client-server setup are: A client app send a request to a server app.  The server app returns a reply.  Some of the basic data communications between client and server are: File transfer - sends name and gets a file.  Web page - sends url and gets a page.  Echo - sends a message and gets it back.  Client server communication uses socket.              To connect to another machine, we need a socket connection. What's a connection?  A relationship between two machines, where two pieces of software know about each other. Those two pieces of software know how to communicate with each other. In other words, they know how to send bits to each other. A socket connection means the two machines have information about each other, including network location (IP address) and TCP port. (If we can use anology, IP address is the phone number and the TCP port is the extension).  A so...

Banker's Algorithm

Banker's algorithm is a deadlock avoidance algorithm. It is named so because this algorithm is used in banking systems to determine whether a loan can be granted or not. Consider there are n account holders in a bank and the sum of the money in all of their accounts is S. Everytime a loan has to be granted by the bank, it subtracts the loan amount from the total money the bank has. Then it checks if that difference is greater than S. It is done because, only then, the bank would have enough money even if all the n account holders draw all their money at once. Banker's algorithm works in a similar way in computers. Whenever a new process is created, it must exactly specify the maximum instances of each resource type that it needs. Let us assume that there are n processes and m resource types. Some data structures are used to implement the banker's algorithm. They are: Available: It is an array of length m . It represents the number of available resourc...

Inter Process Communication-Message Queue

Interprocess communication (IPC) is a set of programming interfaces that allow a programmer to coordinate activities among different program processes that can run concurrently in an operating system. This allows a program to handle many user requests at the same time. Since even a single user request may result in multiple processes running in the operating system on the user's behalf, the processes need to communicate with each other. The IPC interfaces make this possible. Each IPC method has its own advantages and limitations so it is not unusual for a single program to use all of the IPC methods . Message Based Communication Messages are a very general form of communication. Messages can be used to send and receive formatted data streams between arbitrary processes. Messages may have types. This helps in message interpretation. The type may specify appropriate permissions for processes. Usually at the receiver end, messages are put in a queue. Messages may also be fo...