2017-10-04 88 views
0

我正在編寫一個使用udp進行可靠數據傳輸的套接字程序。我以1024字節爲單位將客戶端的映像文件發送到服務器。以下是我的代碼。他們對於大字符串和較小的圖像文件都可以正常工作。但是,當我傳送2.3 MB的圖像時,服務器將只接收2 MB。假設發送的數據包總數是2271.服務器只能收到2211或更少的數據,並且會突然終止。我不知道瑞森。你能解釋我這個嗎?並建議任何解決方案。 下面是我的客戶端代碼使用udp進行可靠的數據傳輸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; 
} 

而我的服務器代碼:

#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

您需要設計一個*協議*以使其位於UDP之上,從而增加「可靠性」。像序列號和確認收到的數據包。或者可能研究在UDP之上的現有可靠的文件傳輸協議,看看你是否可以使用其中的一個。 –

+0

我沒有看到使代碼可靠嗎? – Joe

+2

10使用UDP的任何特定原因?如果您將TCP用於這種場景,則會更合適。而且,當請求太多時,UDP服務器可能會在您不知情的情況下放棄請求。添加序列號,ack等已經在TCP –

回答

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

您傳輸二進制數據,即可能包含\0數據。 strlen不能與二進制數據一起使用,因爲它只是通過在數據中查找\0來確定數據的長度。如果\0buff的中間,則僅發送直到但不包括此\0的部分。

除了:

使用UDP在C

當你做你不關心的可靠性,在所有數據傳輸

可靠的數據傳輸。數據包可能會重新排序,重複或丟失,在大多數情況下您不會注意到它。與TCP相反,UDP本身並不提供任何可靠性。

0

如果預計可靠的傳輸,則建議使用TCP套接字。
但是,如果你想要使用UDP套接字,那麼你必須實現某種自定義協議,你必須等到接收方沒有確認接收到數據包。

在您的客戶端和服務器代碼中,客戶端將數據盲目地發送到服務器,而不關心當前正在服務器端發生的遺漏數據包。

對於一個簡單的解決方法,你可以添加後後
recvfrom(sock,buf,sizeof (buf),0,(struct sockaddr *)&server,sizeof(struct sockaddr));立即
n= sendto(sock,buff,strlen(buff),0,(struct sockaddr *)&server,sizeof(struct sockaddr));
client.c
n= sendto(sock,"ACK",strlen("ACK"),0,(struct sockaddr *)&from,&fromlen); 立即
n = recvfrom(sock,buf,sizeof (buf),0,(struct sockaddr *)&from,&fromlen);server.c

你必須妥善處理文件,因爲不適當的fil處理可能導致輸入和輸出文件不匹配。

如果你想使用UDP與某些文件傳輸協議,我會建議你用XMODEM協議來包裝傳輸和接收。