0

Good day all,

I am trying to send an "object" trough a socket. The structure looks like this:

typedef struct header_file
{
    char chunk_id[4];
    int chunk_size;
    char format[4];
    char subchunk1_id[4];
    int subchunk1_size;
    short int audio_format;
    short int num_channels;
    int sample_rate;
    int byte_rate;
    short int block_align;
    short int bits_per_sample;
    char subchunk2_id[4];
    int subchunk2_size;     
} header;

This is the header structure of a WAV sound file. To read that part for the file, I have this:

FILE* infile = fopen("Sound.wav", "rb");
header *meta = (header*)malloc(sizeof(header));
if(infile){
    fread(meta, 1, sizeof(header), infile);
}

So far so good, if I try to display all information contained in the structure, no problem at all!. However, the part where I am supposed to send this via the socket:

n = write(socket_fd, meta, sizeof(header));

Also works, but on the server side, it only receives this:

RIFF*_

the first 4 characters are those in the array chunk_id of the structure, the chunk size is 352042, which in hexa gives 0x00055F2A

I figured (at least I think so) that because of the zeros in the chunk size, the server read this as character, and guess what 0x00 means? NULL! End of string! How can I sort this out?

Thanks in advance for your help

COMPLETE CLIENT CODE

void* stream_audio(void *arg);

typedef struct header_file
{
    char        chunk_id[4];
    int         chunk_size;
    char        format[4];
    char        subchunk1_id[4];
    int         subchunk1_size;
    short int   audio_format;
    short int   num_channels;
    int         sample_rate;
    int         byte_rate;
    short int   block_align;
    short int   bits_per_sample;
    char        samples_id[4];
    int         samples_size;
} header;

typedef struct header_file* header_p;
int         KEEP_ALIVE     = 1;
int         PORT_NO        = 5002;
char        SERVER_IP[20]  = "127.0.0.1";
pthread_t   t_id;

int main(int argc, char * argv[]) {
    int terr;
    terr        = pthread_create(&t_id, NULL, &stream_audio, NULL);
    pthread_join(t_id, NULL);
}


void* stream_audio(void *arg){
    FILE *              infile = fopen("../files/man1_nb.wav","rb");    // Source WAV audio file
    int                 sockfd, portno, n;
    struct sockaddr_in  serv_addr;
    struct hostent      *server;    
    int                 count   = 0;    // For counting number of frames in wave file.
    char                buff16[2];          // short int used for 16 bit as input data format is 16 bit PCM audio
    header_p            meta    = (header_p)malloc(sizeof(header)); // WAV file metadata fields
    int nb;

    portno = PORT_NO;                           // read port number from arguments
    sockfd = socket(AF_INET, SOCK_STREAM, 0);   // create socket

    if (sockfd < 0) {
        error("ERROR opening socket");
        return ;
    }
    server = gethostbyname(SERVER_IP);            // get host address from argument
    if (server == NULL) {
        fprintf(stderr,"ERROR, no such host\n");
        return ;
    }

    // Create socket and connect to server
    bzero((char *) &serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr,  server->h_length);
    serv_addr.sin_port = htons(portno);
    if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0) 
        error("ERROR connecting");

    // send header WAV file trhough socket
    if (infile){
        fread(meta, 1, sizeof(header), infile);
        meta->chunk_size = 0;
        n = write(sockfd,meta,sizeof(meta));
        if (n < 0) 
            error("ERROR writing to socket");
    } else return;
    int counter = 0;

    while (!feof(infile))
    {
        bzero(buff16, sizeof(buff16));
        nb = fread(buff16,1,1,infile);      // Reading data in chunks of 16 bits (2 bytes)
        n  = write(sockfd,buff16,sizeof(buff16));
        if(!KEEP_ALIVE){
            fclose(infile);
            close(sockfd);
            return;
        }
    }
    fclose(infile);
    close(sockfd);
    return;
}

COMPLETE SERVER CODE

/* A simple server in the internet domain using TCP
   The port number is passed as an argument */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>

void error(char *msg)
{
    perror(msg);
    exit(1);
}

int main(int argc, char *argv[])
{
     int sockfd, newsockfd, portno, clilen;
     char buffer[401];
     struct sockaddr_in serv_addr, cli_addr;
     int n;
     if (argc < 2) {
         fprintf(stderr,"ERROR, no port provided\n");
         exit(1);
     }
     sockfd = socket(AF_INET, SOCK_STREAM, 0);
     if (sockfd < 0) 
        error("ERROR opening socket");
     bzero((char *) &serv_addr, sizeof(serv_addr));
     portno = atoi(argv[1]);
     serv_addr.sin_family = AF_INET;
     serv_addr.sin_addr.s_addr = INADDR_ANY;
     serv_addr.sin_port = htons(portno);
     if (bind(sockfd, (struct sockaddr *) &serv_addr,
              sizeof(serv_addr)) < 0) 
              error("ERROR on binding");

     listen(sockfd,5);
     clilen = sizeof(cli_addr);
     newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
     if (newsockfd < 0) 
          error("ERROR on accept");
     bzero(buffer,401);
     char temper[100];
     sprintf(temper, "/home/user/Documents/manif/bin/receiver%d.wav", portno);
     FILE *receiver = fopen(temper,"wb+");
     int empty = 0;
     while(1){
         memset(buffer,0,400);
         n = read(newsockfd,buffer,400);
        if (n < 0){
            error("ERROR reading from socket");
            break;
        } 
        else if(n>0){
            fwrite(buffer,1, n, receiver);
        } else  break;
        printf("%s   %d\n",buffer, n);
     }
     fclose(receiver);
     close(sockfd);
     return 0; 
}
PhoenixBlue
  • 967
  • 2
  • 9
  • 26
  • 1
    This depends on how the receiver is reading and displaying the data. Please update your question with a [Minimal, Complete, Verifiable Example](http://stackoverflow.com/help/mcve). – dbush Apr 28 '17 at 12:29
  • 1
    [Please see this discussion on why not to cast the return value of `malloc()` and family in `C`.](http://stackoverflow.com/q/605845/2173917). – Sourav Ghosh Apr 28 '17 at 12:36
  • Since your code so far seems reasonable, the problem might be on the receiver's side. – Erich Kitzmueller Apr 28 '17 at 12:37
  • The issue might be with the `printf` you're using... when printing the received data, try: `for (size_t i = 0; i < a; i++) { printf(buffer[i] ? "%c" : "%x", buffer[i]); };` – Myst Apr 29 '17 at 00:22

2 Answers2

0

What you sent over the network is a struct containing multiple elements. However, you're attempting to print what you've read as a string, but it is not a string.

You need to know the format of the data you've received and read it in that format.

If you're only printing for debugging purposes, then loop through the bytes read in and print each one individually as a number. You probably want to do the same on the sender side to be able to compare them.

Also, on the client side, your use of feof is incorrect. You should instead be checking the return value of fread to see if you've reached end-of file. That's most likely the cause of the mismatch.

Community
  • 1
  • 1
dbush
  • 205,898
  • 23
  • 218
  • 273
  • Actually I tried printing just to see what the problem could be. I actually want to save whatever is received into a WAV file, without reading. Just read and write into a binary file, that's all. But the file created on the server side is not the same as the file from the client side... – PhoenixBlue Apr 28 '17 at 12:53
0

printf will print ascii,non ascii(will look line junk on screen) characters till it encounters \0, thats why you are getting only few bytes on screen as the byte next to them must have been \0, if you need to look at the data you need to display each member of your structure individually , or just convert the buffer received over socket to hex while displaying

Pras
  • 4,047
  • 10
  • 20