2017-10-04 4 views
0

J'écris un programme de socket pour un transfert de données fiable en utilisant udp. J'envoie le fichier d'image du client au serveur par morceaux de 1024 octets. Ci-dessous sont mes codes.Ils fonctionnent très bien pour les grandes chaînes et les fichiers image plus petits.Mais quand je transfère l'image de 2,3 Mo, le serveur ne recevra que jusqu'à 2 Mo. Dites si le nombre total de paquets envoyés était 2271. Le serveur ne recevra que jusqu'à 2211 ou moins et se terminera brusquement. Je ne connais pas la raison. Pouvez-vous s'il vous plaît m'expliquer cela? et suggérer une solution. Ci-dessous mon code clienttransfert de données fiable en utilisant udp dans c

#include<stdio.h> 
#include<sys/types.h> 
#include<netinet/in.h> 
#include<netdb.h> 
#include<string.h> 
#include<stdlib.h> 
#include<unistd.h> 
#include<errno.h> 
#include<arpa/inet.h> 

char *itoa(long i,char *s,int dummy_radix) 
{ 
    sprintf(s,"%ld",i); 
    return s; 
} 

int main(int argc, int *argv[]) 
{ 
    int sock,length,n; 
    struct sockaddr_in server,from; 
    struct hostent *hp; 
    long int packets =0; 
    unsigned char buff[1024] = {0}; 


    // checking if hostname and the port address is provided // 
    if(argc!=3) 
    { 
     printf("insufficient arguments\n"); 
     exit(1); 
    } 

    //create a socket// 
    sock = socket(AF_INET,SOCK_DGRAM,0); 

    if(sock<0) 
    { 
     printf("error in opening socket\n"); 
     return 1; 
    } 

    //to get the hostname of the system or the machine// 
    hp= gethostbyname(argv[1]); 

    if(hp==0) 
    { 
     printf("Unknown host\n"); 
     return 1; 
    } 
    //build the server's IP address // 
    bzero((char *)&server,sizeof(server)); 
    bcopy((char*)hp->h_addr,(char *)&server.sin_addr,hp->h_length); 
    server.sin_family = AF_INET; 
    server.sin_port = htons(atoi(argv[2])); 
    length = sizeof(server); 

    /*open the file that we wish to transfer*/ 
    FILE *fp = fopen("landscape.jpeg","rb"); 
    if(fp==NULL) 
    { 
     printf("file open error"); 
     return 1; 
    } 
    fseek(fp,0,SEEK_END); //if exists read the size of the file 
    size_t file_size = ftell(fp); 
    fseek(fp,0,SEEK_SET); 

    printf("size of the file is %d\n", file_size); 

    /*find the number of packets*/ 

    packets = (file_size/1024)+1 ; 

    /*send the number of packets to the server*/ 

    itoa(packets,buff,10); 
    n= sendto(sock,buff,strlen(buff),0,(struct sockaddr *)&server,sizeof(struct sockaddr)); 
     if(n<0) 
     { 
      printf("error in sending message to the serveR"); 
     return 1; 
    } 




    /*Read data from file and send it*/ 
    int packetNum = 0; 
    while(1) 
    { 
     /*First read file in chunks of 1024 bytes */ 

     int nread = fread(buff,1,1024,fp); 
     //printf("Bytes read %d\n",nread); 

     /*if read was success ,send data*/ 
     if(nread>0) 
     { 
      //printf("data sent now is %s\n",buff); 
      n= sendto(sock,buff,strlen(buff),0,(struct sockaddr *)&server,sizeof(struct sockaddr)); 
      printf("Sending %d, numBytes sent: %d\n", packetNum, n); 
      packetNum++; 
        if(n<0) 
        { 
         printf("error in sending message to the server"); 
        fclose(fp); 
        return 1; 
      } 

     } 

     /*There is something tricky going on with the read.. 
     * Either there was error ,or we reached end of file. 
     */ 
     if(nread<1024) 
     { 
      if(feof(fp)) 
       printf("End of file\n"); 

      if(ferror(fp)) 
       printf("Error reading\n"); 
      break; 
     } 

    } 
    close(sock); 
    fclose(fp); 

    return 0; 
} 

Et mon code serveur:

#include<sys/socket.h> 
#include<sys/types.h> 
#include<netinet/in.h> 
#include<netdb.h> 
#include<stdio.h> 
#include<string.h> 
#include<stdlib.h> 
#include<unistd.h> 
#include<errno.h> 
#include<arpa/inet.h> 

int main(int argc, char *argv[]) 
{ 
    int sock,length,fromlen,n; 
    struct sockaddr_in server; 
    struct sockaddr_in from; 
    char buf[1024]; 
    char file_buf[1024]; 
    int packets = 0; 
    int received = 0; 
    FILE *newfp; 
    newfp = fopen("output.jpeg","wb"); 
    if(newfp==NULL) 
    { 
     printf("error opening the file\n"); 
      return 1; 
    } 
    if(argc<2) 
    { 
     fprintf(stderr, "no port number specified\n"); 

     exit(0); 
    } 
    sock = socket(AF_INET,SOCK_DGRAM,0); 
    if(sock<0) 
    { 
     printf("error in opening socket\n"); 
     return 1; 
    } 
    length = sizeof(server); 
    bzero(&server,length); 
    server.sin_family= AF_INET; 
    server.sin_addr.s_addr = INADDR_ANY; 
    server.sin_port = htons(atoi(argv[1])); 
    if(bind(sock,(struct sockaddr*)&server,length)<0) 
    { 
     printf("cannot bind\n"); 
     return 1; 
    } 
    fromlen =sizeof(struct sockaddr_in); 
     n = recvfrom(sock,buf,1024,0,(struct sockaddr *)&from,&fromlen); 
    if(n<0) 
    { 
      printf("recvfrom error\n"); 
      return 1; 
    } 


    packets = atoi(buf); 
    printf("Num packets expected: %d\n", packets); 


    while(received<packets) 
    { 

     n = recvfrom(sock,buf,sizeof (buf),0,(struct sockaddr *)&from,&fromlen);  

      //printf ("%d\n", n); 
     printf("Packet num %d, numBytes received: %d\n", received, n); 

     if(n<0) 
     { 
      printf("recvfrom error\n"); 
      return 1; 
     } 
     //printf("%s",buf); 
     if((fwrite(buf,1,n,newfp)) < n) 
     { 
      printf("error in writing to the file\n"); 
      return 1; 
     } 
     received++; 

    } 
    printf("Finished\n"); 
    fclose(newfp); 
    return 0; 
} 
+4

Vous devez concevoir un * protocole * pour vous asseoir sur UDP, ce qui ajoute de la "fiabilité". Des choses comme les numéros de séquence, et la reconnaissance des paquets reçus. Ou peut-être rechercher des protocoles de transfert de fichiers fiables sur UDP et voir si vous pouvez en utiliser un. –

+0

Je ne vois pas de code pour rendre ceci fiable? .. – Joe

+2

Une raison spécifique d'utiliser UDP? Si vous utilisez TCP pour de tels scénarios, ce sera plus approprié. En outre, lorsqu'il y a trop de demandes, le serveur UDP peut supprimer des demandes sans même que vous le sachiez. L'ajout de numéros de séquence, ack, etc. est déjà géré dans TCP –

Répondre

0
 n= sendto(sock,buff,strlen(buff),0,(struct sockaddr *)&server,sizeof(struct sockaddr)); 

Vous transférez des données binaires, à savoir les données qui pourraient contenir \0. strlen ne peut pas être utilisé avec des données binaires car il détermine simplement la longueur des données en recherchant un \0 à l'intérieur des données. Si un \0 est au milieu de buff, seule la partie jusqu'à \0 sera envoyée.

En dehors de cela:

données fiables transfert à l'aide udp dans c

Pendant que vous faites un transfert de données ne se soucient pas de la fiabilité du tout. Les paquets peuvent être réorganisés, dupliqués ou se perdre et vous ne le remarquerez pas dans la plupart des cas. UDP ne fournit aucune fiabilité par lui-même, contrairement à TCP.

0

Si une transmission fiable est attendue, le socket TCP est recommandé. Mais quand même, si vous voulez aller avec les sockets UDP, alors vous devez implémenter un certain type de protocole personnalisé où vous devez attendre que le récepteur n'ait pas accusé réception de la réception du paquet.

Dans votre code client et serveur, le client envoie des données en aveugle au serveur sans se préoccuper des paquets manquants qui se produisent actuellement sur le serveur.

Pour une solution de contournement simple, vous pouvez ajouter un
recvfrom(sock,buf,sizeof (buf),0,(struct sockaddr *)&server,sizeof(struct sockaddr)); immédiatement après
n= sendto(sock,buff,strlen(buff),0,(struct sockaddr *)&server,sizeof(struct sockaddr));
dans votre client.c et
n= sendto(sock,"ACK",strlen("ACK"),0,(struct sockaddr *)&from,&fromlen); immédiatement après
n = recvfrom(sock,buf,sizeof (buf),0,(struct sockaddr *)&from,&fromlen); dans server.c

Et vous devez prendre soin de la manipulation du fichier correctement parce que le fil incorrect La manipulation peut provoquer une discordance de fichier d'entrée et de sortie.

Si vous souhaitez utiliser UDP avec un protocole de transfert de fichiers, je vous suggère d'envelopper la transmission et la réception avec le protocole XMODEM.