Home > Software design >  pipe with file fread & fwrite send file from one process to another
pipe with file fread & fwrite send file from one process to another

Time:12-10

I Implement a pipe that "transfers" from one process data file size of 100MB to another process.

The Whole Send from one process to the another works well, but it takes soo long... around 2.5 minutes.

I want to change my functions to fread&fwrite to make the function faster instead reading one char each time how I can do it with the pd[0] & pd[1] but I hardly understand how I can change it

Any help will be appreciated!

HERE IS MY CODE:

#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


int main() {
    int fd[2];
    pid_t childpid;
    char readbuffer[65535];

    pipe(fd);

    if ((childpid = fork()) == -1) {
        perror("fork");
        exit(1);
    }

    if (childpid == 0) {
        /* Child process closes up input side of pipe */
        close(fd[0]);

        /* Send "string" through the output side of pipe */
        FILE *fp2 = fopen("data.txt", "rb");

        if (fp2 == NULL) {
            //handle error here
            return -1;
        }
        int c;
        while ((c = getc(fp2)) != EOF) {
            if ((write(fd[1], &c, 1)) < 1) {
                fprintf(stderr, "Write to pipe failed.\n");
                perror("write");
                exit(EXIT_FAILURE);
            }
        }
    } else {
        /* Parent process closes up output side of pipe */
        close(fd[1]);

        /* Read in a string from the pipe */
        char *new_data = "new_data.txt";
        FILE *fp = fopen(new_data, "wb");
        ssize_t num_bytes;
        while (num_bytes = (read(fd[0], readbuffer, sizeof(readbuffer))) > 0) {
            fwrite(readbuffer, 1, num_bytes, fp);
            memset(readbuffer, 0, 65535);
        }
        fclose(fp);
    }
    return 0;
}

EDITED ROUND 2:

#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
    int fd[2];
    pid_t childpid;
    char readbuffer[1024];

    pipe(fd);

    if ((childpid = fork()) == -1) {
        perror("fork");
        exit(1);
    }

    if (childpid == 0) {
        /* Child process closes up input side of pipe */
        close(fd[0]);

        /* Send "string" through the output side of pipe */
        FILE *fp2 = fopen("data.txt", "rb");

        if (fp2 == NULL) {
            //handle error here
            return -1;
        }
        int c;
//        while ((c = getc(fp2)) != EOF) {
//            if ((write(fd[1], &c, 1)) < 1) {
//                fprintf(stderr, "Write to pipe failed.\n");
//                perror("write");
//                exit(EXIT_FAILURE);
//            }
//        }
        ssize_t num_bytes;
        while ((num_bytes = fread(readbuffer, sizeof(readbuffer), 1024,fp2)) > 0) {
            fwrite(readbuffer, 1, num_bytes, fd[1]);
            //memset(readbuffer, 0, 65535);
        }
    } else {
        /* Parent process closes up output side of pipe */
        close(fd[1]);

        /* Read in a string from the pipe */
        char *new_data = "new_data.txt";
        FILE *fp = fopen(new_data, "wb");
        ssize_t num_bytes;
        while ((num_bytes = read(fd[0], readbuffer, sizeof(readbuffer))) > 0) {
            fwrite(readbuffer, 1, num_bytes, fp);
            //memset(readbuffer, 0, 65535);
        }
        fclose(fp);
    }
    return 0;
}

CodePudding user response:

A few issues ...

In your original code, the main issue [speed wise] was using read or write with a length of 1.

Also, although a stream may compensate a bit for fgetc, it is still one byte at a time.

The solution I've come up with is to implement what William Pursell suggested: Use fdopen to attach a stdio stream (i.e. FILE *) to the pipe.

We can do this for both parent and child.

Then, just looping on fread/fwrite in both processes works.

Note that the parent and should do fclose.

And, the parent should wait for the child to complete (e.g. waitpid).

Here is the modified code:

#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/wait.h>

#ifdef DEBUG
#define dbgprt(_fmt...) \
    do { \
        int sverr = errno; \
        fprintf(stderr,_fmt); \
        errno = sverr; \
    } while (0)
#else
#define dbgprt(_fmt...) \
    do { } while (0)
#endif

int
main(void)
{
    int fd[2];
    FILE *fpinp;
    FILE *fpout;
    pid_t childpid;
    int status;
    ssize_t rlen;
    ssize_t wlen;
#if 0
    char buffer[65535];
#else
    char buffer[1024];
#endif

    setlinebuf(stdout);
    setlinebuf(stderr);

    pipe(fd);

    if ((childpid = fork()) == -1) {
        perror("fork");
        exit(1);
    }

    if (childpid == 0) {
        /* Child process closes up input side of pipe */
        close(fd[0]);

        /* Send "string" through the output side of pipe */
        fpinp = fopen("data.txt", "rb");
        if (fpinp == NULL) {
            perror("child/fopen");
            exit(7);
        }

        fpout = fdopen(fd[1],"wb");
        if (fpout == NULL) {
            perror("child/fdopen");
            exit(8);
        }

        while (1) {
            rlen = fread(buffer,1,sizeof(buffer),fpinp);
            dbgprt("child: LOOP rlen=%zd\n",rlen);

            if (rlen < 0) {
                perror("child/fread");
                exit(9);
            }

            if (rlen <= 0)
                break;

            wlen = fwrite(buffer,1,rlen,fpout);
            dbgprt("child: LOOP wlen=%zd\n",wlen);

            if (wlen < 0) {
                perror("child/fwrite");
                exit(9);
            }
        }

        fclose(fpinp);
        fclose(fpout);

        exit(0);
    }
    else {
        /* Parent process closes up output side of pipe */
        close(fd[1]);

        /* Read in a string from the pipe */
        char *new_data = "new_data.txt";
        fpout = fopen(new_data, "wb");
        if (fpout == NULL) {
            perror("parent/fopen");
            exit(3);
        }

        fpinp = fdopen(fd[0],"rb");
        if (fpinp == NULL) {
            perror("parent/fdopen");
            exit(4);
        }

        while (1) {
            rlen = fread(buffer, 1, sizeof(buffer), fpinp);
            dbgprt("parent: LOOP rlen=%zd\n",rlen);
            if (rlen < 0) {
                perror("parent/fread");
                exit(5);
            }
            if (rlen <= 0)
                break;

            wlen = fwrite(buffer, 1, rlen, fpout);
            dbgprt("parent: LOOP wlen=%zd\n",wlen);
            if (wlen < 0) {
                perror("parent/fwrite");
                exit(6);
            }
        }

        fclose(fpinp);
        fclose(fpout);

        waitpid(childpid,&status,0);
        dbgprt("status=%8.8X\n",status);
    }

    return 0;
}
  • Related