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

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

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

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 ответа

Решение

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

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

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

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

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

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

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

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

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

Это ты read от fd[0] а также write в fd[1]

Другие вопросы по тегам