как канал становится однонаправленным, когда мы получаем два файловых дескриптора, вызывая функцию pipe () в C

#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.org

2. Это шестая версия традиционных ядер Unix: minnie.tuhs.org/cgi-bin/utree.pl?file=V6/usr/sys/ken/pipe.c . Возможно, новое ядро имеет другую реализацию, но имеет ту же концепцию.

3. Но OP пометил свой вопрос как Linux.