Как правильно прочитать длину сообщения в трубе? - PullRequest
0 голосов
/ 29 октября 2018

Я делаю программу, в которой ребенок читает сообщение из канала, написанного родителем. Но вопрос: возможно ли, что ребенок начинает читать в канале ДО того, как родитель закончил писать в нем? Если это так, ребенок прочитает фрагмент сообщения и прекратит работу. Как я могу убедиться, что все сообщение будет прочитано без чтения 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 голосов
/ 29 октября 2018

возможно ли, что ребенок начинает читать в канале ДО того, как родитель закончил писать в нем?

Это не проблема. read(2) вызывайте блок, пока не будет что прочитать, если вы не пометите дескриптор файла как неблокирующий.

Как я могу убедиться, что все сообщение будет прочитано без чтения char с помощью char и зацикливания при наличии символов?

Дело в том, что каналы не понимают, что такое "сообщение", его начало или конец; это просто поток байтов, передаваемых с одного конца на другой. Подробнее см. pipe(7).

Если у вас есть какие-либо маркеры «начало», «конец», «длина», то вам нужно создать / деконструировать себя. Вы всегда можете задать read(2) больше, и, если возвращается не то, что было запрошено, вы можете сделать вывод, что это все, что есть (проверяя возвращаемое значение и errno, чтобы узнать точную причину этого: конец -файл, ошибка ввода-вывода и т. д.).

0 голосов
/ 29 октября 2018

С того момента, как вы вызываете fork, вы можете быть уверены, что все написанное в канале будет прочитано дочерним процессом:

  • Если родитель пишет что-то, а потомок не читает его сразу, он будет оставаться в буфере канала до тех пор, пока потомок не прочитает.
  • Если ребенок начинает читать до того, как родитель начинает писать, тогда read ребенка будет блокироваться, пока не будет что-то прочитать.

Возможно, вы захотите close(p[1]) после записи в него в родительском элементе, чтобы ребенок мог правильно распознать конец данных. Это не проблема в вашем конкретном случае, поскольку вы записываете фиксированный объем данных и читаете точно такой же объем, но в общем случае лучше всего закрыть канал после записи в него.

Не о чем беспокоиться. Единственное, что было бы лучше, если бы у вас была действительно длинная строка, это читать и писать в чанках и обрабатывать каждый чанк отдельно в дочерних элементах, чтобы ваша программа не использовала слишком много памяти, чтобы сохранить то, что ей не нужно.

Кроме того, примечание: при использовании строковых литералов "like this" вам не нужно добавлять терминатор NUL \0, он добавляется автоматически.

...