#c #linux #pipe
#c #linux #канал
Вопрос:
Я читаю документацию функции pipe и столкнулся с этим
pipe() creates a pipe, a unidirectional data channel that can be used for interprocess communication
Но она возвращает два файловых дескриптора. Один для чтения и один для записи. Чего я не понимаю?
Комментарии:
1. Данные в канале передаются только в одну сторону.
2. Возможно, определение POSIX
pipe()
сформулировано лучше? Кстати,pipe()
это не определено в стандарте C11 .
Ответ №1:
Вы можете рассматривать два файловых дескриптора как концы канала. Вы можете записывать только в один конец, а читать — только с другого. Если бы вы хотели двустороннюю связь между двумя процессами, вам понадобились бы два канала. Поскольку информация в канале течет в одном направлении, каналы называются однонаправленными.
---------- ----------
| | pipe | |
| fd1>=======================>fd2 |
| | ---> | |
| | | |
| | pipe | |
| fd3<=======================<fd4 |
| | <--- | |
---------- ----------
В отличие от этого, вы можете записывать на любой конец сокета, и все, что вы записываете на один конец, может быть прочитано другим концом. Существует два потока данных, поэтому одной пары сокетов было бы достаточно для двусторонней связи между двумя процессами. Поскольку информация в сокете течет в обоих направлениях, сокеты называются двунаправленными.
---------- ----------
| | socket | |
| | ---> | |
| fd1=========================fd2 |
| | <--- | |
| | | |
---------- ----------
Ответ №2:
Канал реализован в виде буфера FIFO внутри ядра Linux.
Каждый конец буфера соответствует файловому дескриптору. Смотрите канал (7) и читайте Advanced Linux Programming, затем системные вызовы (2)
Для примеров использования канала (2) загляните в исходный код оболочек с открытым исходным кодом, таких как sash или GNU bash, и изучите их динамическое поведение с помощью strace(1) и gdb(1).
Вы можете загрузить, затем изучить и перекомпилировать исходный код программного обеспечения с открытым исходным кодом (возможно, используя GCC как gcc -g -Wall
) из таких мест, как github или gitlab.
В простых случаях вы могли бы использовать popen(3) (исходный код которого находится внутри GNU glibc или musl-libc). Не забудьте проверить на сбой и каким-то образом (или тщательно сконструировать) команду, переданную popen
Если вам более любопытно, изучите исходный код ядра Linux и спросите у kernelnewbies после прочтения учебника по операционным системам.
Ответ №3:
В каналах Linux дочерний элемент записывает, а родительский считывает, или наоборот; это означает, что данные могут передаваться только в одну сторону. pipe()
создает пару файловых дескрипторов: один указывает на конец чтения, а другой — на конец записи. Данные, записанные на конец записи, могут быть прочитаны концом чтения, таким образом, являясь однонаправленным каналом межпроцессной связи.
Сокеты: сокет — это дуплексное соединение, по которому вы можете отправлять данные в обоих направлениях; вы можете отправлять данные в тот же сокет, из которого вы читаете. Вы можете закрыть сокет в одном направлении и по-прежнему отправлять данные в другом направлении. Сокеты, настроенные как потоки, являются двунаправленными, а управление выполняется по шаблону клиент / сервер.
Комментарии:
1. Являются ли сокеты двунаправленными?
Ответ №4:
Вызов канала выдает два файловых дескриптора, pfd [0] для чтения и pfd [1] для записи. Вы можете записать в pfd [1] и прочитать то, что вы написали из pfd [0]. Но в этом нет никакого преимущества. Канал предназначен для обмена данными между двумя связанными процессами. Итак, после создания канала выполняется разветвление, и оба файловых дескриптора доступны родительскому и дочернему процессам. Один процесс использует pfd [1] для записи, а другой процесс использует pfd [0] для чтения. И происходит обмен данными.
Предположим, родительский процесс настроен на запись в pfd [1], а дочерний процесс настроен на чтение в pfd [0]. Тогда родительский процесс не может прочитать pfd [0], а дочерний процесс записать в pfd [1] и ожидать, что обмен данными состоится, потому что внутри канала есть только один поток данных. Это имитирует реальные трубы, используемые для полива растений. Вода течет только в одном направлении. Как указал @ikegami, если вам нужна двусторонняя связь между процессами, следует использовать два канала.
Ответ №5:
Каналы обеспечивают однонаправленный канал связи между процессами. Как и у любых других каналов, канал имеет конец чтения и конец записи. Данные, записанные на конец канала для записи, могут быть считаны с конца канала для чтения, что-то вроде смещения чтения и записи в каналах.
Вот фактический системный вызов канала: Дополнительная информация
/*
* The sys-pipe entry.
* Allocate an inode on the root device.
* Allocate 2 file structures.
* Put it all together with flags.
*/
pipe()
{
register *ip, *rf, *wf;
int r;
ip = ialloc(rootdev);
if(ip == NULL)
return;
rf = falloc();
if(rf == NULL) {
iput(ip);
return;
}
r = u.u_ar0[R0];
wf = falloc();
if(wf == NULL) {
rf->f_count = 0;
u.u_ofile[r] = NULL;
iput(ip);
return;
}
u.u_ar0[R1] = u.u_ar0[R0]; /* wf's fd */
u.u_ar0[R0] = r; /* rf's fd */
wf->f_flag = FWRITE|FPIPE;
wf->f_inode = ip;
rf->f_flag = FREAD|FPIPE;
rf->f_inode = ip;
ip->i_count = 2;
ip->i_flag = IACC|IUPD;
ip->i_mode = IALLOC;
}
Комментарии:
1. Исходный код
pipe
системного вызова для Linux не этот. Он включен kernel.org2. Это шестая версия традиционных ядер Unix: minnie.tuhs.org/cgi-bin/utree.pl?file=V6/usr/sys/ken/pipe.c . Возможно, новое ядро имеет другую реализацию, но имеет ту же концепцию.
3. Но OP пометил свой вопрос как Linux.