File Transfer using UDP Socket in C

In this tutorial, we are going to build a file transfer program in the C programming language. Here we are going to use the UDP (User Datagram Protocol) socket to connect the client and the server.

Table of Content:

  1. What is UDP?
  2. Project structure
  3. Client
  4. Server
  5. Run the code
  6. Conclusion

What is UDP?

The UDP or User Datagram Protocol, a communication protocol used for transferring data across the network. It is an unreliable and connectionless communication protocol as it does not establish a proper connection between the client and the server. It is used for time-sensitive applications like gaming, playing videos, or Domain Name System (DNS) lookups. UDP is a faster communication protocol as compared to the TCP

Some of the features of UDP are:

  • It’s a connectionless communication protocol.
  • It is much faster in comparison with TCP.

READ MORE: File Transfer using TCP Socket in C


Project Structure

The project is divided into two files:

  1. client.c
  2. server.c
  3. client.txt

The client.c file contains the code for the client-side, which read the client.txt file and sends it to the server and the server.c file receives the data from the client and saves it in a text file.

In the program, communication takes place as follows:

  • The server is started.
  • The client read the text file and send data to the server.
  • The server creates a text file.
  • The server received the data from the client and write it into the text file.
  • The client sends the END command to close the data transfer.
  • The client disconnected from the server.
  • The server is closed.

Client

First, we are going to include all the required header files.

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

Next, we are going to start our main function. Inside the main function, we are going to define the IP address and the port number.

 int main(){

  // Defining the IP and Port
  char *ip = "127.0.0.1";
  int port = 8080;

Make sure that both the client and the server use the same IP address and the port number.

Now, all the variables are initialized.

  // Defining variables
  int server_sockfd;
  struct sockaddr_in server_addr;
  FILE *fp;
  char *filename = "client.txt";

After defining the IP address, port number and other variables, we are going to create the UDP socket.

If any error occurred, while creating the UDP socket, we are going to print the error message.

  // Creating a UDP socket
  server_sockfd = socket(AF_INET, SOCK_DGRAM, 0);
  if (server_sockfd < 0){
    perror("[ERROR] socket error");
    exit(1);
  }

Here:

  • AF_INET: refers to the communication domain. Here we use IPv4.
  • SOCK_DGRAM: refers to the type of communication between the client and server. Here, we use the UDP.
  • 0: refers to the protocol value for the Internet Protocol (IP), which is 0.

Next, we fill the value in the server socket structure.

  server_addr.sin_family = AF_INET;
  server_addr.sin_port = port;
  server_addr.sin_addr.s_addr = inet_addr(ip);

Now, we read the client.txt text file. If some error occurred while reading the text file, we are going to print the error message.

  // Reading the text file
  fp = fopen(filename, "r");
  if (fp == NULL){
    perror("[ERROR] reading the file");
    exit(1);
  }

After reading the text file, we send its data to the server using the send_file_data function.

  // Sending the file data to the server
  send_file_data(fp, server_sockfd, server_addr);

At last, we print some message on the screen and close the connection from the UDP server.

  printf("[SUCCESS] Data transfer complete.\n");
  printf("[CLOSING] Disconnecting from the server.\n");

  close(server_sockfd);
  return 0;
}

Now, we go through the send_file_data function in details.

void send_file_data(FILE *fp, int sockfd, struct sockaddr_in addr){

The function takes the following parameters:

  1. FILE *fp: It is the file pointer that is used for reading the data present within the text file.
  2. int sockfd: It is the server socket.
  3. struct sockaddr_in addr: This refers to the client structure where all the client details are going to be saved.
  int n;
  char buffer[SIZE];

After defining the variables, we are going to read the text file data and send it to the server.

// Sending the data
  while(fgets(buffer, SIZE, fp) != NULL){
    printf("[SENDING] Data: %s", buffer);

    n = sendto(sockfd, buffer, SIZE, 0, (struct sockaddr*)&addr, sizeof(addr));
    if (n == -1){
      perror("[ERROR] sending data to the server.");
      exit(1);
    }
    bzero(buffer, SIZE);

  }

In the above code:

  1. We read the text file data within a while loop.
  2. Then we print the text data.
  3. Next, we send that data to the server using the sendto function.
  4. If any error occurred while sending the data then we are going to print the error message.
  5. At last, we are going to fill the array buffer with zero.
  // Sending the 'END'
  strcpy(buffer, "END");
  sendto(sockfd, buffer, SIZE, 0, (struct sockaddr*)&addr, sizeof(addr));

After the complete data is sent from the text file, we sent the END text to the server. The END is used to tell the server that the file transfer is complete.

Next, we close the file pointer fp and return.

  fclose(fp);
  return;
}

Complete Code – CLIENT.C

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

void send_file_data(FILE *fp, int sockfd, struct sockaddr_in addr){
  int n;
  char buffer[SIZE];

  // Sending the data
  while(fgets(buffer, SIZE, fp) != NULL){
    printf("[SENDING] Data: %s", buffer);

    n = sendto(sockfd, buffer, SIZE, 0, (struct sockaddr*)&addr, sizeof(addr));
    if (n == -1){
      perror("[ERROR] sending data to the server.");
      exit(1);
    }
    bzero(buffer, SIZE);

  }

  // Sending the 'END'
  strcpy(buffer, "END");
  sendto(sockfd, buffer, SIZE, 0, (struct sockaddr*)&addr, sizeof(addr));

  fclose(fp);
  return;
}

int main(){

  // Defining the IP and Port
  char *ip = "127.0.0.1";
  int port = 8080;

  // Defining variables
  int server_sockfd;
  struct sockaddr_in server_addr;
  FILE *fp;
  char *filename = "client.txt";

  // Creating a UDP socket
  server_sockfd = socket(AF_INET, SOCK_DGRAM, 0);
  if (server_sockfd < 0){
    perror("[ERROR] socket error");
    exit(1);
  }
  server_addr.sin_family = AF_INET;
  server_addr.sin_port = port;
  server_addr.sin_addr.s_addr = inet_addr(ip);

  // Reading the text file
  fp = fopen(filename, "r");
  if (fp == NULL){
    perror("[ERROR] reading the file");
    exit(1);
  }

  // Sending the file data to the server
  send_file_data(fp, server_sockfd, server_addr);

  printf("[SUCCESS] Data transfer complete.\n");
  printf("[CLOSING] Disconnecting from the server.\n");

  close(server_sockfd);
  return 0;
}

Server

Some initial parts of the server code are the same as the client code.

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

int main(){

  // Defining the IP and Port
  char *ip = "127.0.0.1";
  int port = 8080;

  // Defining variables
  int server_sockfd;
  struct sockaddr_in server_addr, client_addr;
  char buffer[SIZE];
  int e;

  // Creating a UDP socket
  server_sockfd = socket(AF_INET, SOCK_DGRAM, 0);
  if (server_sockfd < 0){
    perror("[ERROR] socket error");
    exit(1);
  }
  server_addr.sin_family = AF_INET;
  server_addr.sin_port = port;
  server_addr.sin_addr.s_addr = inet_addr(ip);

We start by including all the required header files at the top of the server.c file. Next, we start the main function do the followings:

  1. Define the IP address and the port number.
  2. We define the required variables and structure.
  3. Next, we create a UDP socket and fill the required values in the server_addr structure.
  e = bind(server_sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));
  if (e < 0){
    perror("[ERROR] bind error");
    exit(1);
  }

Now, we use the bind function to bind the IP address and the port number. If any error occurred in the bind function, then an error message will be printed.

  printf("[STARTING] UDP File Server started. \n");
  write_file(server_sockfd, client_addr);

  printf("[SUCCESS] Data transfer complete.\n");
  printf("[CLOSING] Closing the server.\n");

  close(server_sockfd);
  return 0;
}

Now the UDP server is ready to receive the data from the client. The server uses the function write_file to receive the data from the client and write it into a text file. Next, we print some message and close the server and return.

Now, we go into the details of the write_file function.

void write_file(int sockfd, struct sockaddr_in addr){

The write_file function takes the following parameters:

  1. int sockfd: It is the server socket.
  2. struct sockaddr_in addr: This refers to the client structure where all the client details are going to be saved.
  FILE *fp;
  char *filename = "server.txt";
  int n;
  char buffer[SIZE];
  socklen_t addr_size;

Next, some variables are declared.

  // Creating a file.
  fp = fopen(filename, "w");

We now create a text file, where we save all the data received from the client-side.

  // Receiving the data and writing it into the file.
  while(1){

    addr_size = sizeof(addr);
    n = recvfrom(sockfd, buffer, SIZE, 0, (struct sockaddr*)&addr, &addr_size);

    if (strcmp(buffer, "END") == 0){
      break;
      return;
    }

    printf("[RECEVING] Data: %s", buffer);
    fprintf(fp, "%s", buffer);
    bzero(buffer, SIZE);

  }

Next, comes an infinite while loop, where we receive the data from the client. If the client sends the END command, then we stop the loop, else, we print the data on the screen and write the data into the text file. At last, we fill the buffer array with zero.

  fclose(fp);
  return;
}

After exiting the loop, we close the file pointer and return it from the function.

Complete Code – SERVER.C

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

#define SIZE 1024

void write_file(int sockfd, struct sockaddr_in addr){
  FILE *fp;
  char *filename = "server.txt";
  int n;
  char buffer[SIZE];
  socklen_t addr_size;

  // Creating a file.
  fp = fopen(filename, "w");

  // Receiving the data and writing it into the file.
  while(1){

    addr_size = sizeof(addr);
    n = recvfrom(sockfd, buffer, SIZE, 0, (struct sockaddr*)&addr, &addr_size);

    if (strcmp(buffer, "END") == 0){
      break;
      return;
    }

    printf("[RECEVING] Data: %s", buffer);
    fprintf(fp, "%s", buffer);
    bzero(buffer, SIZE);

  }

  fclose(fp);
  return;
}

int main(){

  // Defining the IP and Port
  char *ip = "127.0.0.1";
  int port = 8080;

  // Defining variables
  int server_sockfd;
  struct sockaddr_in server_addr, client_addr;
  char buffer[SIZE];
  int e;

  // Creating a UDP socket
  server_sockfd = socket(AF_INET, SOCK_DGRAM, 0);
  if (server_sockfd < 0){
    perror("[ERROR] socket error");
    exit(1);
  }
  server_addr.sin_family = AF_INET;
  server_addr.sin_port = port;
  server_addr.sin_addr.s_addr = inet_addr(ip);

  e = bind(server_sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));
  if (e < 0){
    perror("[ERROR] bind error");
    exit(1);
  }

  printf("[STARTING] UDP File Server started. \n");
  write_file(server_sockfd, client_addr);

  printf("[SUCCESS] Data transfer complete.\n");
  printf("[CLOSING] Closing the server.\n");

  close(server_sockfd);

  return 0;
}

Run the Code

To run the code follow the following commands:

gcc server.c -o server
gcc client.c -o client

Next, run the server file and then the client file.

./server
Server console screen
Server console screen
./client
Client console screen
Client console screen

In the end, a server.txt file will be created containing all the text from the client.txt file.


Conclusion

I hope, I was able to give you some new knowledge. If I did then share this article.

Leave A Comment