0

我需要将文件从一个应用程序传输到同一台机器上的另一个应用程序。我编写了传输数据包结构的代码,该数据包结构具有以下字段:

  • 序号
  • 圆形的
  • data,这是一个unsigned char指示要传输的数据
  • lengthread ,表示使用函数读取了多少字节
  • crc,这是目前的默认字符串

和一个参数last,表示它是最后一个数据包,因此可以关闭文件和连接。

此代码非常适用于 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;
}
4

1 回答 1

1

我已经遇到了与套接字类似的问题,因为我正在发送“unsigned char []”的缓冲区,并接收到“char []”的缓冲区,我认为这不是你的问题,因为你没有在有符号的范围内进行任何操作阵列,但任何方式都可以避免这些演员阵容,而且值得一试。

利用

unsigned char buf[MAXBUFLEN];

代替

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 标志,但我还是更喜欢每次检查读取的数据量。

于 2013-04-16T14:21:30.707 回答