Чтение нужного количества данных из канала при получении вывода от execvp

Это всего лишь небольшая часть большой программы, но я пытаюсь получить вывод от execvp. У меня правильно настроен execvp с dup2, который направляет его в канал. Моя проблема возникает, когда дело доходит до использования read для чтения полной длины канала. Я не знаю, насколько велик вывод execvp каждый раз, потому что он может отличаться в зависимости от ввода.

    int fd[2];
    pipe(fd);
    pid_t pid = fork();
    if (pid == 0) {
        close(fd[0]);
        dup2(fd[1], 1);
        execvp(msg.v,(char *[]){msg.v,NULL});
    } else if (pid > 0) {
        close(fd[1]);
        read(fd[0],msg.v,....);
    }

Я пробовал несколько разных размеров для чтения, но этого либо недостаточно, либо в конце я получаю случайный мусор. Я знаю, что вы можете использовать popen и несколько других вещей из stdio, но это требуется для задания, что мы их не используем Im отказ от других способов получить результат.

Еще немного бесполезной информации, вся программа является частью сервера. Я создаю сервер и клиент. Запустите сервер, дайте клиенту команду терминала, он отправляет ее на сервер через поток INET и отправляет вывод обратно клиенту, чтобы отобразить вывод без stdio.


person Mintybacon    schedule 07.08.2012    source источник


Ответы (2)


Вы должны обратить внимание на то, сколько данных read возвращается в ваш буфер. Пока read возвращает положительные числа, у вас есть больше данных. Когда программа завершится, она закроет свой конец pipe, и ваш read вернет 0.

} else if (pid > 0) {
    close(fd[1]);
    ssize_t r = read(fd[0],buf,bufsz);
    if (r > 0) do {
        /* ... do something with r bytes in buf */
        r = read(fd[0],buf,bufsz);
    } while (r > 0);
    if (r < 0) {
        perror("read");
        /*...*/
    }
}

Если вы видите, что read выдает ошибку «Прерванный системный вызов», значит, вы столкнулись со случаем EINTR, о котором упоминал caf. В этом случае вы снова перезапустите свой read.

        for (;;) {
            r = read(fd[0],buf,bufsz);
            if (r != -1 || errno != EINTR) break;
        }

Я предполагаю, что вы не выполняете неблокирующий ввод-вывод, поэтому вы не столкнетесь с сообщением «Ресурс временно недоступен».

person jxh    schedule 07.08.2012
comment
Я не упомянул об этом, но мы можем использовать stdio, который не выполняет предварительный ввод-вывод, поэтому я смог выполнить цикл и использовать sprintf, чтобы собрать воедино мое сообщение, спасибо, это помогло! - person Mintybacon; 07.08.2012

Вы продолжаете чтение до тех пор, пока read() не вернет 0, что указывает на EOF (или -1 с errno, установленным на постоянную ошибку, которая отличается от EAGAIN или EINTR).

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

person caf    schedule 07.08.2012