lte__
lte__

Reputation: 7576

C - Sending struct array over pipe

I'm trying to send an array of structs through a pipe. I have a struct:

typedef struct visitordata {
    char name[80];
    char email[80];
    int id;
    char reg_time[9];
}visitordata;

Then I do

//...
//ds is the number of struct entries to be stored
visitordata* V;
V = (visitordata*)malloc(ds * sizeof(visitordata));

pid_t child = fork();
if(child < 0) {
    perror("Fork error");
        exit(1);
    }
 else if (child > 0) { //parent process
    write(pipefd[1], &V, sizeof(V));
    close(pipefd[1]);
    fflush(NULL);
    pause();

    sleep(1);
    pause();
    kill(child,SIGTERM);                
    waitpid(child, &status, 0);
}
else { //child process
    visitordata* data;
    close(pipefd[1]);

    read(pipefd[0], &data, sizeof(data));
    close(pipefd[0]);
    flush(NULL);
    for (i = 0; i < ds; ++i) {
        printf("Received: %s\r\n", data[i].name);
    }

    kill(getppid(), SIGUSR1);
    pause();                
}

But then, if I have two rows for input, the Received part only prints out one row with the string "free" (which I think comed from the username on the server: freeze@server:) and then Received: without anything else. What am I doing wrong?

EDIT

Updated the code as per suggestions:

visitordata* V;
V = (visitordata*)malloc(ds * sizeof(visitordata));

pid_t child = fork();
if(child < 0) {
    perror("Fork error");
        exit(1);
    }
 else if (child > 0) { //parent process
    write(pipefd[1], V, ds * sizeof(V));
    close(pipefd[1]);
    fflush(NULL);
    pause();

    sleep(1);
    pause();
    kill(child,SIGTERM);                
    waitpid(child, &status, 0);
}
else { //child process
    visitordata* data;
    data = (visitordata*)malloc(ds * sizeof(visitordata));
    close(pipefd[1]);

    read(pipefd[0], data, ds * sizeof(data));
    close(pipefd[0]);
    flush(NULL);
    for (i = 0; i < ds; ++i) {
        printf("Received: %s\r\n", data[i].name);
    }

    kill(getppid(), SIGUSR1);
    pause();                
}

Now my output is like this:

Received: 0▒:▒0▒:▒ 
Received:

EDIT 2

Updated

read(pipefd[0], data, ds * sizeof(data));

and

write(pipefd[1], V, ds * sizeof(V));

to

read(pipefd[0], data, ds * sizeof(visitordata));

and

write(pipefd[1], V, ds * sizeof(visitordata));

Now my output is:

Received: 0Tɢ0Tɢ
Received:

Upvotes: 1

Views: 8226

Answers (3)

Andrew Henle
Andrew Henle

Reputation: 1

read() and write() read and write up to the number of bytes requested. Per the POSIX standard for write():

The write() function shall attempt to write nbyte bytes from the buffer pointed to by buf to the file associated with the open file descriptor, fildes.

...

RETURN VALUE

Upon successful completion, these functions shall return the number of bytes actually written to the file associated with fildes. This number shall never be greater than nbyte. Otherwise, -1 shall be returned and errno set to indicate the error.

Your code never checks the results of write - you merely hope it works. To ensure the entire requested number of bytes is written, you need something like this:

size_t bytesToWrite = ds * sizeof(visitordata);
size_t totalWritten = 0;

for ( ;; )
{
    ssize_t bytesWritten = write( pipefd[1], V + totalWritten,
        bytesToWrite - totalWritten );
    if ( bytesWritten <= 0 )
    {
        break;
    }

    totalWritten += bytesWritten;
}

You need to handle read() similarly.

Upvotes: 2

Paul R
Paul R

Reputation: 212979

You are passing incorrect parameters to both write and read. You need to pass a pointer to the actual data, and the length of the data in bytes.

So:

write(pipefd[1], &V, sizeof(V));

should be:

write(pipefd[1], V, ds * sizeof(visitordata)); // note: 2 fixes here

and similarly:

read(pipefd[0], &data, sizeof(data));

should be:

read(pipefd[0], data, ds * sizeof(visitordata)); // note: 2 fixes here also


Also, as noted by @Someprogrammerdude, you data pointer is not initialised (it's just a wild pointer). Change:

visitordata* data;

to:

visitordata* data = malloc(ds * sizeof(visitordata));

Upvotes: 0

user2496748
user2496748

Reputation: 65

This smells:

write(pipefd[1], &V, sizeof(V));

Maybe this is better:

write(pipefd[1], V, sizeof(V));

The receving part is also problematic. Where do allocate a buffer for it? visitordata* data;

Upvotes: -1

Related Questions