Какой конец канала предназначен для ввода, а какой для вывода?

#c #pipe #file-descriptor

#c #канал #файловый дескриптор

Вопрос:

Недавно я начал подозревать, что неправильно использую концы каналов:

Из справочных страниц:

pipe() создает канал. ..pipefd[0] ссылается на считываемый конец канала. pipefd[1] ссылается на конец канала записи.

Итак, на мой взгляд, у меня это было так:

                 .---------------------------.
               /                            /
              | pipedfd[0]       pipedfd[1]|  |
process1 ---> |                            | -----> process2
              | input                output|  |
               ____________________________/
  

Однако код, который у меня есть здесь и работает, предполагает иное:

 #include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(void)
{
  int pipedfd[2];
  char buf[30];

  pipe(pipedfd);
  printf("writing to file descriptor #%dn", pipedfd[1]);
  write(pipedfd[1], "test", 5);
  printf("reading from file descriptor #%dn", pipedfd[0]);
  read(pipedfd[0], buf, 5);
  printf("read "%s"n", buf);

  return 0;
}
  

А именно, он записывает на выход (?) канала и считывает с входа (?) канала?

Комментарии:

1. Попробуйте проверить возврат ошибки при чтении и записи, и все станет ясно.

2. Прочитанный конец канала = откуда вы читаете = pipefd[0] (не та часть, в которую вы записываете , как на вашей диаграмме). Звучит довольно просто.

3. @Jon Когда я думаю о физической трубе, я представляю ее как имеющую один угол для ввода (получения воды) и один для вывода (выпуска воды).). Я не думаю, что вода будет поступать (записываться) на выход трубы. На мой взгляд, это противоречит интуиции. И нет, я не пламмер.

4. @Pithikos: Метафора физического канала в этом случае действительно приносит больше вреда, чем пользы. 🙂

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

Ответ №1:

В двух словах, поменяйте местами числа 0 и 1 в вашей диаграмме, и вы получите то, что я опишу ниже.

С справочной страницы Mac OS X:

Функция pipe() создает канал (объект, который допускает однонаправленный поток данных) и выделяет пару файловых дескрипторов. Первый дескриптор подключается к концу чтения канала; второй подключается к концу записи.

Данные, записанные в файлы [1], отображаются в файлах [0] (т.Е. могут быть прочитаны из них). Это позволяет отправлять выходные данные одной программы в другую программу: стандартный вывод источника настроен на конец канала записи; стандартный ввод приемника настроен на конец канала чтения. Сам канал сохраняется до тех пор, пока все связанные с ним дескрипторы не будут закрыты.

Я опишу, как это часто используется, это может прояснить ситуацию. Представьте, что у вас есть процесс, и вы хотите создать дочерний процесс, которому вы хотите отправлять команды.

  • Сначала вы вызываете pipe и получаете два файловых дескриптора.
  • Затем вы вызываете fork , чтобы создать дочерний элемент.
    • В дочернем элементе вы закрываете дескриптор файла записи ( fd[1] ) и оставляете открытым дескриптор для чтения.
    • В родительском файле вы делаете обратное: вы закрываете дескриптор файла для чтения ( fd[0] ) и оставляете открытым дескриптор для записи.
  • Теперь родитель может записывать в «свою» часть канала ( fd[1] ), а дочерний элемент может читать на другом ( fd[0] ).

Закрытие не обязательно, но обычно выполняется. Если вам нужна двусторонняя связь, вам либо нужен второй набор файловых дескрипторов плюс второй вызов pipe , либо вы используете двусторонний канал, такой как доменные сокеты Unix или именованный канал.

Ответ №2:

Справочная страница Linux для pipe устранения неоднозначности выглядит следующим образом:

Данные, записанные на конец канала записи, буферизуются ядром до тех пор, пока они не будут считаны с конца канала чтения.

То есть вы read от fd[0] и write до fd[1]

Комментарии:

1. @JonPurdy: Да, это то, что делает его код, его диаграмма (и понимание) меняются местами