【问题标题】:Using pipe to pass data between two processes continuously使用管道在两个进程之间连续传递数据
【发布时间】:2016-12-02 16:11:31
【问题描述】:

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

一个孩子应该继续从标准输入读取,将它读取的内容传递到管道,而另一个孩子应该从管道读取并将其打印到标准输出。

我设法让它工作,但只有一次,在读取数字后的第二次迭代中,我得到: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--;
    }
}

【问题讨论】:

  • 你认为open(pipe_descs[WRITE]); 会做什么?其次,为什么要在循环中关闭它?废话。

标签: c unix process pipe fork


【解决方案1】:

问题 #1

如果你要关闭作者(close(pipe_descs[WRITE]);),你不能继续使用它!要么删除该语句,要么在关闭管道后退出循环。

问题 #2

open(pipe_descs[WRITE]) 毫无意义!摆脱它。

问题 #3

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

write(..., sizeof(int)) != sizeof(int) 不(必然)指示错误情况。如果没有发生错误,那么write 没有将errno 设置为有意义的东西,所以你得到的错误信息是没有意义的。

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

        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 返回的金额少于请求的金额也不是错误。因此,它也需要在 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;
}

【讨论】:

  • 这是一个最小的例子,但在我的实际代码中我写的是结构体,所以不写或读整个结构体一定是一个错误不是吗?
  • @kuhaku, 不,write 不写整个结构并不一定表示错误。不编写整个结构将是您的编码错误,但我向您展示了如何反复调用 write 以确保写入整个结构。
  • 在管道中,write 是原子的(只要长度小于 PIPE_BUF 至少应该是 512),所以写一个 int 应该返回它的大小,如果不是,就发生了错误。
  • @Jean-Baptiste Yunès,这无关紧要有两个原因。 1)发布的程序,更重要的是给出错误的实际程序,发送的不仅仅是一个int,所以管道可能已经填满了。 2)你仍然需要阅读直到write返回-1才能得到错误信息。
  • 当一个管道满了,那么写就会阻塞,这就是阻塞模式下的管道语义。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-16
  • 1970-01-01
  • 2011-07-11
  • 2020-01-06
相关资源
最近更新 更多