j10
j10

Reputation: 2261

Binary file cannot be transferred whereas text file can be

I need to transder a file from one application to another application on the same machine. I wrote code which transfers a packet structure which has fields like:

and a parameter, last, indicating that it is the last packet so that the file and connection can be closed.

This code works perfectly for ASCII files, but, when I use it to transfer a binary file, the diff of two files don't match. I am not able to figure out what the problem is. Can some one help me?

Here is the code for my sender. It connects to receiver on port 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;
}

and here is the code for my receiver :

#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;
}

Upvotes: 0

Views: 216

Answers (1)

Jonatan Goebel
Jonatan Goebel

Reputation: 1139

I already had a similar problem with socket because I was sending a buffer of "unsigned char[]", and receiving into a buffer of "char[]", I dont think is your problem because you do not do any manipulation within the signed array, but any way is good to avoid those casts, and it worth the shot.

use

unsigned char buf[MAXBUFLEN];

instead of

char buf[MAXBUFLEN];

Also clear your buffer before receiving the packet, and check the value of "numbytes" before continuing the process. Example:

    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.");
    }

Or try to pass the MSG_WAITALL flag when using recvfrom to read entire blocks of memory, but I still prefer to check the amount of data read every time.

Upvotes: 1

Related Questions