2013-04-16 26 views
0

我需要將文件從一個應用程序傳輸到同一臺計算機上的另一個應用程序。我寫代碼傳送,其具有像字段的分組的結構:無法傳輸二進制文件,而文本文件可能是

  • SEQ沒有
  • 數據,這是一個unsigned char指示數據要傳送
  • 長度爲,表示使用read函數已讀取多少個字節
  • CRC,這是默認字符串截至目前

和參數,最後,這表明它是最後的分組,使得該文件,並連接可以關閉。

此代碼完美適用於ASCII文件,但是,當我使用它來傳輸二進制文件時,兩個文件的差異不匹配。我無法弄清楚問題所在。有人能幫我嗎?

這是我的發件人的代碼。它連接到接收機上的端口4950

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <errno.h> 
#include <string.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <arpa/inet.h> 
#include <netdb.h> 
#define DATA 170 
#define SERVERPORT "4950"  // the port users will be connecting to 

typedef struct packet_ { 
    unsigned short int seq; 
    unsigned short int round; 
    unsigned short int last; 
    unsigned short int length; 
    unsigned char data[DATA]; 
    unsigned char crc[17]; 
} packet; 

int main(int argc, char *argv[]) 
{ 
    int sockfd; 
    struct addrinfo hints, *servinfo, *p; 
    int rv; 
    int numbytes; 
    int max_seq_no = 10; 
    packet send; 
    FILE *fp; 
    unsigned short int seq =0, round =0; 
    long int totalBytes = 0; 
    unsigned short int bytes_read =0; 

    if (argc != 3) { 
     fprintf(stderr,"usage: talker hostname message\n"); 
     exit(1); 
    } 

    memset(&hints, 0, sizeof hints); 
    hints.ai_family = AF_UNSPEC; 
    hints.ai_socktype = SOCK_DGRAM; 
    hints.ai_flags = AI_PASSIVE; // use my IP 
    if ((rv = getaddrinfo(NULL, SERVERPORT, &hints, &servinfo)) != 0) { 
     fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); 
     return 1; 
    } 

    // loop through all the results and make a socket 
    for(p = servinfo; p != NULL; p = p->ai_next) { 
     if ((sockfd = socket(p->ai_family, p->ai_socktype, 
          p->ai_protocol)) == -1) { 
      perror("talker: socket"); 
      continue; 
     } 
     break; 
    } 

    if (p == NULL) { 
     fprintf(stderr, "talker: failed to bind socket\n"); 
     return 2; 
    } 

    fp = fopen("wilde-tiobe.txt", "rb"); 
    printf("Size of packet : %d", sizeof send); 

    while (1) { 
     memset((void *) &send, '\0', sizeof send); 

     send.seq = seq; 
     send.round = round; 
     memset(send.data, '\0', DATA); 
     bytes_read = read(fileno(fp), send.data, DATA); 
     send.length = bytes_read; 
     if (bytes_read < DATA) { 
      send.last = 1; 
      printf("****last byte***\n"); 
     } 
     strcpy(send.crc, "yet to calcula\0"); 
     totalBytes+= bytes_read; 

     //if(bytes_read == 0) break; 

     if ((numbytes = sendto(sockfd, &send, sizeof send, 0, 
           p->ai_addr, p->ai_addrlen)) == -1) { 
      perror("talker: sendto"); 
      exit(1); 
     } 
     usleep(60000); 
     if (send.last) break; 
    } 

    fclose(fp); 
    printf("Total bytes transferred : %lu\n", totalBytes); 

    freeaddrinfo(servinfo); 

    close(sockfd); 

    return 0; 
} 

,這裏是我的接收器的代碼:

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

#define MYPORT "4950" // the port users will be connecting to 

#define MAXBUFLEN 196 
#define DATA 170 

typedef struct packet_ { 
    unsigned short int seq; 
    unsigned short int round; 
    unsigned short int last; 
    unsigned short int length; 
    unsigned char data[DATA]; 
    unsigned char crc[17]; 
} packet; 

// get sockaddr, IPv4 or IPv6: 
void *get_in_addr(struct sockaddr *sa) 
{ 
    if (sa->sa_family == AF_INET) { 
     return &(((struct sockaddr_in*)sa)->sin_addr); 
    } 

    return &(((struct sockaddr_in6*)sa)->sin6_addr); 
} 

int main(void) 
{ 
    int sockfd; 
    struct addrinfo hints, *servinfo, *p; 
    int rv; 
    FILE *fp; 
    int numbytes; 
    struct sockaddr_storage their_addr; 
    char buf[MAXBUFLEN]; 
    socklen_t addr_len; 
    char s[INET6_ADDRSTRLEN]; 
    packet * recv, recv_packet; 
    fp = fopen("wtf.bmp", "wb"); 

    printf("size of packet :%d", sizeof(packet)); 
    memset(&hints, 0, sizeof hints); 

    hints.ai_family = AF_UNSPEC; // set to AF_INET to force IPv4 
    hints.ai_socktype = SOCK_DGRAM; 
    hints.ai_flags = AI_PASSIVE; // use my IP 

    if ((rv = getaddrinfo(NULL, MYPORT, &hints, &servinfo)) != 0) { 
     fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); 
     return 1; 
    } 

    // loop through all the results and bind to the first we can 
    for(p = servinfo; p != NULL; p = p->ai_next) { 
     if ((sockfd = socket(p->ai_family, p->ai_socktype, 
          p->ai_protocol)) == -1) { 
      perror("listener: socket"); 
      continue; 
     } 

     if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) { 
      close(sockfd); 
      perror("listener: bind"); 
      continue; 
     } 

     break; 
    } 

    if (p == NULL) { 
     fprintf(stderr, "listener: failed to bind socket\n"); 
     return 2; 
    } 

    freeaddrinfo(servinfo); 

    addr_len = sizeof their_addr; 

    while(1) { 
     printf("listener: waiting to recvfrom...\n"); 
     if ((numbytes = recvfrom(sockfd, buf, MAXBUFLEN , 0, 
           (struct sockaddr *)&their_addr, 
            &addr_len)) == -1) { 
      perror("recvfrom"); 
      exit(1); 
     } 
     printf("listener: got packet from %s\n", 
       inet_ntop(their_addr.ss_family, 
         get_in_addr((struct sockaddr *)&their_addr), 
         s, sizeof s)); 
     printf("listener: packet is %d bytes long\n", numbytes); 
     //printf("listener: packet contains \"%s\"\n", buf); 
     recv = (packet *) buf; 
     if (!recv_packet.data) { 
      printf("NO memory\n"); 
      break; 
     } 
     memset(&recv_packet, 0, sizeof recv_packet); 
     recv_packet.seq = recv->seq; 
     recv_packet.round = recv->round; 
     recv_packet.last = recv->last; 
     recv_packet.length = recv->length; 
     memset(recv_packet.data, '\0', DATA); 
     strncpy(recv_packet.data, recv->data, recv_packet.length); 
     strncpy(recv_packet.crc, recv->crc, 17); 
     //printf(" len: %hu and data: %s \n", recv_packet.length, recv_packet.data); 
     write(fileno(fp), recv_packet.data, recv_packet.length); 
     if (recv_packet.last) { 
      printf("Last packet\n"); 
      break; 
     } 
    } 

    fclose(fp); 
    close(sockfd); 

    return 0; 
} 
+1

可能不是你爲什麼會遇到問題,但是當你使用'FILE *'時,當你可以使用'fwrite'時,爲什麼你要跳過使用'write'?如果你解釋了你在二進制文件中看到的差異(使用「od」或類似的工具應該有助於檢查二進制文件),這將有所幫助。 –

+1

可能是一個愚蠢的問題,但是當你說差異不匹配時,你使用的工具,可以區分二進制文件? –

+0

@AnishRam:檢查了這一點:http://www.cryst.bbk.ac.uk/CCSG/unix/unix_for_beginners/cmp.html – j10

回答

1

因爲我送的「無符號的char [緩衝我已經與插座類似的問題]「,並接收到一個」char []「的緩衝區中,我不認爲是你的問題,因爲你沒有在簽名數組中進行任何操作,但是任何方法都可以避免這些劇集,並且值得拍攝。的

char buf[MAXBUFLEN]; 

使用

unsigned char buf[MAXBUFLEN]; 

而不是接收數據包之前一併清除緩衝區,並繼續處理之前檢查 「的numBytes」 的值。 例子:

printf("listener: waiting to recvfrom...\n"); 
    memset(buff, 0, sizeof(buff)); 
    numbytes=0; 
    while ((numbytes += recvfrom(sockfd, &buf[numbytes], MAXBUFLEN - numbytes , 0, 
           (struct sockaddr *)&their_addr, 
           &addr_len)) < sizeof(packet)) 
     printf("Oops, the package is not full, lets read it again."); 
    } 

,或者嘗試使用recvfrom的讀取內存的整個塊時傳遞MSG_WAITALL標誌,但我還是喜歡的數據讀取每次檢查量。

+0

是的,我想這就是問題讓我檢查出我的壞 – j10

+0

它的工作原理,但我在recvfrom做了以下改變,而不是在buf中接收,我直接在包結構中接收,但我仍然會嘗試使用unsigned char。感謝您的建議。 – j10