如何准确读取管道中的消息长度?

时间:2018-10-29 11:06:04

标签: c unix pipe

我正在编写一个程序,让孩子从父母编写的管道中读取消息。但是问题是:在父级完成书写之前,孩子可能会开始在管道中阅读吗?如果是这样,孩子将阅读该消息的一部分并终止。我如何确保所有消息都将被读取而不会逐字符读取char并在有char时循环循环?

这是我的代码:

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

#define TEXT_LENGTH 20

int main(void) {
    int p[2];
    char msg[TEXT_LENGTH];

    if (pipe(p) == -1) {
        perror("Error");
        exit(1);
    }

    switch (fork()) {
        case -1:
            perror("Error");
            exit(1);
        case 0:
            close(p[1]);
            read(p[0], &msg, TEXT_LENGTH);
            printf("%s\n", msg);
            exit(0);
        default:
            close(p[0]);
            strcpy(msg, "Very long text ...\0");
            write(p[1], &msg, TEXT_LENGTH);
            wait(NULL);
    }

    return 0;
}

现在它可以工作了,但是如果文本很长,在孩子进入阅读之前,父级是否有时间写它?

2 个答案:

答案 0 :(得分:0)

从调用fork的那一刻起,您可以确保子进程会读取管道上写入的所有内容:

  • 如果父母写了一些东西,但孩子没有立即读到它,它将保留在管道缓冲区中,直到孩子阅读为止。
  • 如果孩子在父母开始写作之前就开始阅读,则孩子的read会阻塞直到有需要阅读的东西。

您可能想在父中写入close(p[1])之后,以便孩子正确识别数据的结尾。在您的特定情况下,这不是问题,因为您写入了固定数量的数据并读取了完全相同的数量,但是通常最好在写入后关闭管道。

没有太多的担心。如果您的字符串很长,那么唯一的更好的办法就是分块读写,然后在子进程中分别处理每个块,这样程序就不会使用太多内存来保留不需要的内容。

另外,请注意:使用字符串文字"like this"时,不必添加NUL终止符\0,它会自动添加。

答案 1 :(得分:0)

  

在父级完成书写之前,子级是否有可能开始在管道中读取?

这不是问题。 read(2)调用块,直到有一些要读取的内容为止,除非您将文件描述符标记为非阻塞。

  

我如何确保所有消息都被读取而不会逐字符读取char并在有char时循环循环?

问题是管道不了解什么是“消息”或其开始或结束;它只是从一端传递到另一端的字节流。阅读pipe(7)了解详情。

如果您有任何“开始”,“结束”,“长度”标记,那么您需要自己构建/解构。您总是可以询问 $ouput,如果返回的结果少于要求,则可以得出结论:(检查返回值和read(2)可以知道产生错误的确切原因)那是:文件结束,I / O错误等)。