Какой конец канала предназначен для ввода, а какой для вывода? - PullRequest
4 голосов
/ 23 октября 2011

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

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

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 #%d\n", pipedfd[1]);
  write(pipedfd[1], "test", 5);
  printf("reading from file descriptor #%d\n", pipedfd[0]);
  read(pipedfd[0], buf, 5);
  printf("read \"%s\"\n", buf);

  return 0;
}

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

Ответы [ 2 ]

4 голосов
/ 23 октября 2011

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

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

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

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

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

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

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

2 голосов
/ 23 октября 2011

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

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

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

...