使用管道在两个进程之间连续传递数据

Using pipe to pass data between two processes continuously

我正在尝试让两个 child 进程通过管道相互通信。

一个 child 应该继续从 stdin 读取,将读取的内容传递给管道,而另一个 child 应该从管道读取并将其打印到 stdout。

我设法让它工作,但只有一次,在读取数字后的第二次迭代中,我得到:write failed: Bad file descriptor

我不知道我做错了什么...

#define READ 0
#define WRITE 1
int main(){

    int pipe_descs[2];
    int retval = pipe(pipe_descs);
    int pid = fork();
    if(pid == 0){   //son that reads from stdin and writes to pipe 
        close(pipe_descs[READ]);
        int x;
        while(1){
            open(pipe_descs[WRITE]);
            scanf("%d", &x);
            if(write(pipe_descs[WRITE], &x, sizeof(int)) != sizeof(int)){
                perror("write failed");
                exit(EXIT_FAILURE);
            }
            close(pipe_descs[WRITE]);
        }
        perror("");
    }
    else if(pid > 0){   //parent

        int pid = fork();
        if(pid == 0){   //son that reads from pipe and write to stdout 
            int pipestat;
            int readNum;
            close(pipe_descs[WRITE]);
            while((pipestat = read(pipe_descs[READ], &readNum, sizeof(int))) > 0){

                printf("read: %d \n", readNum);
                //close(pipe_descs[READ]);
                //open(pipe_descs[READ]);
            }
            if (pipestat==-1) {
                perror("");
                fprintf(stderr, "error to pipe... exiting\n");
                exit(EXIT_FAILURE);
            }
        }
    }

    int status;
    int i = 2;
    while (i > 0){
        wait(&status);
        i--;
    }
}

问题 #1

如果您要关闭编写器(close(pipe_descs[WRITE]);),您将无法继续使用它!要么删除该语句,要么在关闭管道后退出循环。

问题 #2

open(pipe_descs[WRITE])没有意义!摆脱那个。

问题 #3

[如果您的系统符合POSIX.1-2001,并且您写入的数量小于PIPE_BUF,那么您可以忽略此部分。]

write(..., sizeof(int)) != sizeof(int) 不(必然)指示错误情况。如果没有发生错误,那么 write 没有将 errno 设置为有意义的内容,因此您获得的错误消息没有意义。

由于write写的少于请求的数量不是错误,所以需要在循环中调用它。替换

        if(write(pipe_descs[WRITE], &x, sizeof(int)) != sizeof(int)){
            perror("write failed");
            exit(EXIT_FAILURE);
        }

        my_write(pipe_descs[WRITE], &x, sizeof(x));

并添加

void my_write(int fd, const void *buf, size_t bytes_to_write) {
    while (bytes_to_write > 0) {
        ssize_t bytes_written = write(fd, buf, bytes_to_write);
        if (bytes_written == -1) {
            perror("write failed");
            exit(EXIT_FAILURE);
        }

        buf            += bytes_written;
        bytes_to_write -= bytes_written;
    }
}

类似的,read到return小于请求的数量不是错误。因此,它也需要在 a 循环中调用。替换

        while((pipestat = read(pipe_descs[READ], &readNum, sizeof(int))) > 0){

            printf("read: %d \n", readNum);
            //close(pipe_descs[READ]);
            //open(pipe_descs[READ]);
        }
        if (pipestat==-1) {
            perror("");
            fprintf(stderr, "error to pipe... exiting\n");
            exit(EXIT_FAILURE);
        }

        while (my_read(pipe_descs[READ], &readNum, sizeof(readNum))) {
            printf("read: %d \n", readNum);
        }

并添加

int my_read(int fd, void *buf, size_t bytes_to_read) {
    int has_read = 0;
    while (bytes_to_read > 0) {
        ssize_t bytes_read = read(fd, buf, bytes_to_read);
        if (bytes_read == -1) {
            perror("read failed");
            exit(EXIT_FAILURE);
        }

        if (bytes_read == 0) {
             if (has_read) {
                 fprintf(stderr, "read failed: Premature EOF");
                 exit(EXIT_FAILURE);
             }

             return 0;
        }

        has_read = 1;

        buf           += bytes_read;
        bytes_to_read -= bytes_read;
    }

    return 1;
}