Linux network programming based on UDP to achieve reliable file transfer example

  • 2020-04-02 02:37:44
  • OfStack

Anyone who knows the network transport protocol knows that file transfer using TCP is simple. Compared to TCP, UDP is a connectionless and unreliable transport protocol, so we need to consider packet loss and first-come-first-served (packet order) issues, so we need to solve these two problems if we want to implement UDP transmission files. The method is to number the packet, receive and store it in the order of the packet. After receiving the packet, the receiving end sends the confirmation information to the sending end. After receiving the confirmation data, the sending end continues to send the next packet.

The following is a sample program based on the C implementation under Linux, which defines the structure of a package containing the data and the packet header, which contains the packet number and data size. After testing, the program can successfully transfer a video file.

The specific implementation code is as follows:

The server code is as follows:


 
#include<sys/types.h> 
#include<sys/socket.h> 
#include<unistd.h> 
#include<netinet/in.h> 
#include<arpa/inet.h> 
#include<stdio.h> 
#include<stdlib.h> 
#include<errno.h> 
#include<netdb.h> 
#include<stdarg.h> 
#include<string.h> 
 
#define SERVER_PORT 8000 
#define BUFFER_SIZE 1024 
#define FILE_NAME_MAX_SIZE 512 
 
 
typedef struct 
{ 
  int id; 
  int buf_size; 
}PackInfo; 
 
 
struct SendPack 
{ 
  PackInfo head; 
  char buf[BUFFER_SIZE]; 
} data; 
 
 
int main() 
{ 
   
  int send_id = 0; 
 
   
  int receive_id = 0; 
 
   
  struct sockaddr_in server_addr; 
  bzero(&server_addr, sizeof(server_addr)); 
  server_addr.sin_family = AF_INET; 
  server_addr.sin_addr.s_addr = htonl(INADDR_ANY); 
  server_addr.sin_port = htons(SERVER_PORT); 
 
   
  int server_socket_fd = socket(AF_INET, SOCK_DGRAM, 0); 
  if(server_socket_fd == -1) 
  { 
    perror("Create Socket Failed:"); 
    exit(1); 
  } 
 
   
  if(-1 == (bind(server_socket_fd,(struct sockaddr*)&server_addr,sizeof(server_addr)))) 
  { 
    perror("Server Bind Failed:"); 
    exit(1); 
  } 
 
   
  while(1) 
  {   
     
    struct sockaddr_in client_addr; 
    socklen_t client_addr_length = sizeof(client_addr); 
 
     
    char buffer[BUFFER_SIZE]; 
    bzero(buffer, BUFFER_SIZE); 
    if(recvfrom(server_socket_fd, buffer, BUFFER_SIZE,0,(struct sockaddr*)&client_addr, &client_addr_length) == -1) 
    { 
      perror("Receive Data Failed:"); 
      exit(1); 
    } 
 
     
    char file_name[FILE_NAME_MAX_SIZE+1]; 
    bzero(file_name,FILE_NAME_MAX_SIZE+1); 
    strncpy(file_name, buffer, strlen(buffer)>FILE_NAME_MAX_SIZE?FILE_NAME_MAX_SIZE:strlen(buffer)); 
    printf("%sn", file_name); 
 
     
    FILE *fp = fopen(file_name, "r"); 
    if(NULL == fp) 
    { 
      printf("File:%s Not Found.n", file_name); 
    } 
    else 
    { 
      int len = 0; 
       
      while(1) 
      { 
        PackInfo pack_info; 
 
        if(receive_id == send_id) 
        { 
          ++send_id; 
          if((len = fread(data.buf, sizeof(char), BUFFER_SIZE, fp)) > 0) 
          { 
            data.head.id = send_id;  
            data.head.buf_size = len;  
            if(sendto(server_socket_fd, (char*)&data, sizeof(data), 0, (struct sockaddr*)&client_addr, client_addr_length) < 0) 
            { 
              perror("Send File Failed:"); 
              break; 
            } 
             
            recvfrom(server_socket_fd, (char*)&pack_info, sizeof(pack_info), 0, (struct sockaddr*)&client_addr, &client_addr_length); 
            receive_id = pack_info.id;  
          } 
          else 
          { 
            break; 
          } 
        } 
        else 
        { 
           
          if(sendto(server_socket_fd, (char*)&data, sizeof(data), 0, (struct sockaddr*)&client_addr, client_addr_length) < 0) 
          { 
            perror("Send File Failed:"); 
            break; 
          } 
           
          recvfrom(server_socket_fd, (char*)&pack_info, sizeof(pack_info), 0, (struct sockaddr*)&client_addr, &client_addr_length); 
          receive_id = pack_info.id;  
        } 
      } 
       
      fclose(fp); 
      printf("File:%s Transfer Successful!n", file_name); 
    } 
  } 
  close(server_socket_fd); 
  return 0; 
} 

The client code is as follows:


 
#include<sys/types.h> 
#include<sys/socket.h> 
#include<unistd.h> 
#include<netinet/in.h> 
#include<arpa/inet.h> 
#include<stdio.h> 
#include<stdlib.h> 
#include<errno.h> 
#include<netdb.h> 
#include<stdarg.h> 
#include<string.h> 
 
#define SERVER_PORT 8000 
#define BUFFER_SIZE 1024 
#define FILE_NAME_MAX_SIZE 512 
 
 
typedef struct  
{ 
  int id; 
  int buf_size; 
}PackInfo; 
 
 
struct RecvPack 
{ 
  PackInfo head; 
  char buf[BUFFER_SIZE]; 
} data; 
 
 
int main() 
{ 
  int id = 1; 
 
   
  struct sockaddr_in server_addr; 
  bzero(&server_addr, sizeof(server_addr)); 
  server_addr.sin_family = AF_INET; 
  server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); 
  server_addr.sin_port = htons(SERVER_PORT); 
  socklen_t server_addr_length = sizeof(server_addr); 
 
   
  int client_socket_fd = socket(AF_INET, SOCK_DGRAM, 0); 
  if(client_socket_fd < 0) 
  { 
    perror("Create Socket Failed:"); 
    exit(1); 
  } 
 
   
  char file_name[FILE_NAME_MAX_SIZE+1]; 
  bzero(file_name, FILE_NAME_MAX_SIZE+1); 
  printf("Please Input File Name On Server: "); 
  scanf("%s", file_name); 
 
  char buffer[BUFFER_SIZE]; 
  bzero(buffer, BUFFER_SIZE); 
  strncpy(buffer, file_name, strlen(file_name)>BUFFER_SIZE?BUFFER_SIZE:strlen(file_name)); 
 
   
  if(sendto(client_socket_fd, buffer, BUFFER_SIZE,0,(struct sockaddr*)&server_addr,server_addr_length) < 0) 
  { 
    perror("Send File Name Failed:"); 
    exit(1); 
  } 
 
   
  FILE *fp = fopen(file_name, "w"); 
  if(NULL == fp) 
  { 
    printf("File:t%s Can Not Open To Writen", file_name);  
    exit(1); 
  } 
 
   
  int len = 0; 
  while(1) 
  { 
    PackInfo pack_info; 
 
    if((len = recvfrom(client_socket_fd, (char*)&data, sizeof(data), 0, (struct sockaddr*)&server_addr,&server_addr_length)) > 0) 
    { 
      if(data.head.id == id) 
      { 
        pack_info.id = data.head.id; 
        pack_info.buf_size = data.head.buf_size; 
        ++id; 
         
        if(sendto(client_socket_fd, (char*)&pack_info, sizeof(pack_info), 0, (struct sockaddr*)&server_addr, server_addr_length) < 0) 
        { 
          printf("Send confirm information failed!"); 
        } 
         
        if(fwrite(data.buf, sizeof(char), data.head.buf_size, fp) < data.head.buf_size) 
        { 
          printf("File:t%s Write Failedn", file_name); 
          break; 
        } 
      } 
      else if(data.head.id < id)  
      { 
        pack_info.id = data.head.id; 
        pack_info.buf_size = data.head.buf_size; 
         
        if(sendto(client_socket_fd, (char*)&pack_info, sizeof(pack_info), 0, (struct sockaddr*)&server_addr, server_addr_length) < 0) 
        { 
          printf("Send confirm information failed!"); 
        } 
      } 
      else 
      { 
 
      } 
    } 
    else 
    { 
      break; 
    } 
  } 
 
  printf("Receive File:t%s From Server IP Successful!n", file_name); 
  fclose(fp); 
  close(client_socket_fd); 
  return 0; 
}

Interested friends can start to test the program, I believe that the Linux under the C language network programming to bring some help.


Related articles: