#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: Да, это то, что делает его код, его диаграмма (и понимание) меняются местами