named pipes в Unix

    Я давно читал про них, ещё когда учился основам юникс, но как-то не было нужды с ними работать. И, вот, нужда возникла.

    Некая программа (допустим, foo) не умеет писать вывод в stdout, только в файл. Даже "-" в качестве имени файла всего лишь создаёт файл с названием "-" [большинство умных программ под unix знают, что одиночный минус вместо имени файла означает вывод в stdout]. Аналогично она отвергает и /dev/stdout.

    Другая же программа, обрабатывающая результаты первой, допустим, bar, читает из stdin и пишет в stdout. (если быть точным, первое — это трейсер специального вида, дающий двоичный дамп, а второе — конвертор, печатающий их же в человекочитаемом виде).

    Нужно их объединить в конвеер.

    Некрасивый вариант — использование обычного файла. Записал, прочитал.

    Есть куда более красивый вариант — это именованные пайпы. Так как у пайпа есть имя, мы можем передать его как файл первой программе, а потом передать содержимое другой.

    Выглядит это так:

    mkfifo mypipe
    cat mypipe | bar &
    foo mypipe&
    rm mypipe
    



    Пайп в файловой системе выглядит так:
    ls -l mypipe
    prw-r--r-- 1 root root     0 May 24 12:23 mypipe
    

    (акцент на букву 'p' первым символом).

    Как это работает? Фактически, fifo aka named pipe — это «обыкновенный pipe», примерно такой, который кодируется палкой "|". Однако, у него есть ИМЯ и это имя можно указывать всюду, где требуется файл.

    Программа, которая пишет в именованный пайп, ведёт себя с ним как с файлом. Т.е. пишет себе и пишет. Программа, которая читает — аналогично. Читает себе и читает. Чтение идёт в том порядке, как была осуществлена запись (FIFO — first in first out). Положения относительно пайпа (слева/справа) определяются тем, кто читает, а кто пишет.

    Важная же особенность пайпа — способность тормознуть читающую/пищущую программу, если буфер пуст/переполнен.

    Рассмотрим на примере чтения. Программа пишет в пайп одну строчку в секунду. Программа чтения читает с максимально возможной скоростью. Программа «вычитывает» всё, что было в буфере, и посылает следующий запрос. Ядро этот запрос задерживает до того момента, пока не появятся данные. Таким образом, можно не париться с синхронизацией — появятся данные, программа-обработчик получит управление обратно из read() и обработает очередную порцию данных.

    Similar posts

    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 39

    • UFO just landed and posted this here
        +5
        Нет.
          +3
          примерно как в файлы устройств :)
          • UFO just landed and posted this here
              0
              А например? Интересно ведь)
              • UFO just landed and posted this here
            +4
            Сами данные на диск не пишутся, но запись inode происходит (за исключением виртуальных фс, типа tmpfs). При записи в пайп, ядро перехватывает операцию и перенаправляет данные в буфер, размер которого, обычно, 4 кб. Если буфер наполнился, то процесс, который пишет в пайп, «морозится» до тех пор, пока другой процесс не откроет пайп «с другого конца», т.е. не начнет читать из него. Во время чтения происходит, в принципе, тоже самое, только «морозится» читающий процесс до тех пор, пока не присоединится пишущий/не начнет писать.

            // Вот как-то так… (с)
              0
              А можно ли настроить объем буфера? Это иногда бывает полезно, когда поток идет неравномерно.
                0
                10 секунд гугления (от сюда):
                You have to recompile the kernel.
                The constant PIPE_SIZE establishes the number of bytes allocated for a pipe (the size of the pipe buffer; in fact, the size of pipe buffer is PAGE_SIZE). The constant PIPE_BUF (limits.h) defines the atomic operational limit (atomic writes to a pipe).


                В большинстве случаев 4 кб буфера вполне хватает. Даже при неравномерных потоках. Лично у меня не было случаев, чтобы мне 4 кб не хватило.
            0
            /dev/stduot ваша программка foo тоже не понимает?
              +1
              xentrace /dev/stdout
              Cannot output to a TTY, specify a log file.
                +2
                Как насчёт xentrace /dev/stdout | cat
                В этом случае /dev/stdout уже будет не на терминал указывать, а на безымянный пайп.
                  0
                  Да, в таком виде оно сработало. В принципе, можно использовать, спасибо.
              0
              ох, а я писал в файл и смотрел в сторону виртуальных fs. Спасибо.
                0
                есть ещё фишка как демон мониторинга изменений в файлах. но с именоваными пайпами данный трёк прикольнее
                • UFO just landed and posted this here
                    0
                    с пайпами я не знаю получится ли. демон в принципе следит за доступам к файлам, то вполне возможно, что и запись в пайпу словит. попробуйте, интересно. он называется inotify
                +2
                Стоит добавить, что пайпы работают только в пределах локального компьютера(положить файл на nfs раздел можно, но данные будут на каждой машине свои), тк это просто участок в памяти.
                  +7
                  О сколько нам открытий чудных
                  Несёт простой linux user manual.
                    0
                    В обычном linux user manual про это с большой вероятностью ни слова.

                    А в unix-manual оно есть, но читают их единицы…
                    0
                    круто! я почему-то не сомневался что в юниксе есть решение для такой проблемы.
                    подскажите, а под винду нету похожего? :) а мне нужно было что-то подобное когда-то написать, я делал через анус…
                      0
                      Поскольку всё хорошее в виндах спёрто с линукса (а всё плохое с мака), то есть:

                        +1
                        >Поскольку всё хорошее в виндах спёрто с линукса

                        Не с линукса, а с юникса.
                          0
                          прошу прощения. Многое хорошее спёрто из юникса.
                        +1
                          0
                          спасибо. я помню что смотрел в эту сторону, но были какие-то проблемы (либо мне было просто лень искать как их решить). если я правильно помню, то имя у этого пайпа будет только в формате \\.\<путь>. а его не помимают многие программы (либо я опять затупил и можно что-то с этим сделать)
                            +3
                            А, ты про возможность использовать это на уровне пользователя? Зачем пользователю windows named pipe? У него же есть Особая Кнопка, на которую нужно нажимать. Named Pipe для разработчиков, обычным пользователям не положено пользоваться UNC-путями.

                            … Если ms реализует named pipe для пользователей в VBS, то это будет выглядеть примерно так:

                            pipe=wbem.obj.create.named_pipe(«2.322»,«name»);
                            pipe.init(65536,SECURE_UUID,hWnd);
                            pipe.prepare(3,WINDOWS_PREPARE_NAMED_PIPE);
                            pipe.accept(W_INCOMING,1);
                            pipe.accept(W_OUTGOING,1);
                            pipe.accept(W_MODE,WP_FIFO);
                            hPipe=pipe.get_handler(NULL,NULL,NULL,NULL,NULL,2,NULL);


                              0
                              ну как бы да. хотелось бы нормального способа все сделать в консоли как в юниксе. обычному пользователю может и не надо, а вот админам вполне может пригодиться :) всеравно спасибо
                                0
                                Админам это тоже не пригодится, потому что майкрософт не считает нужным предоставлять удобные функции пользователю.
                            +5
                            О чём и речь. Либо ты виндовый пользователь, либо тебе удобно. Одновременно этого не совместить.
                          +3
                          Ещё одно применение named pipe — обход ограничения на командный пайп — нельзя читать и писать в файл одновременно.
                          Вот например одноразовый http-debugger на пайпе и netcat:
                          $ mkfifo ncproxy
                          $ cat < ncproxy | nc -l -p 8888 | tee connlog-in | nc google.com 80 | tee connlog-out | cat > ncproxy &

                          Таким способом можно зацикливать пайп относительно ввода/вывода.
                            +1
                            Мой мозк!
                            0
                            Если не перевести процесс bar в фон, то след. команду ввести будет нельзя (ну если только жать ^z). Поэтому лучше сделать так:
                            mkfifo mypipe
                            cat mypipe | bar &       <<---- 
                            foo mypipe&
                            rm mypipe


                            Хотя я предпочитаю запускать подобные процессы так (мне так как-то нагляднее):
                            foo mypipe & cat mypipe | bar
                              0
                              Да, я их переставил местами, забыл в фон убрать. Сек.
                              +2
                              Ещё отличное применение fifo-файлы находят там, где происходит последовательная обработка больших объёмов данных.

                              Например, при выгрузке/загрузке дампов из/в Oracle экономится очень много времени и места:

                              mkfifo f
                              exp user/pwd tables=HUGE_TABLE file=f &
                              gzip <f >HUGE_TABLE.dmp.gz
                              rm -f f
                              
                                +1
                                Статья полезная, но инфы в ней мало =(

                                Выглядит как будто человек только что узнал про них, но на практике применить еще руки не дошли.

                                Нет инфы, можно ли использовать 3 разные программы, которые пишут в один и тот же пайп, который обрабатывает 4-ая программа. Ну и так далее, как говорится, тонкости использования
                                  0
                                  Я не «только узнал», а «применил в жизни в первый раз». Насчёт нескольких программ… Не проверял. А надо?
                                    0
                                    Думаю, что надо. Например, ситуация, когда в один и тот же лог пишут одновременно nginx, apache и все это выводит в sendxmpp

                                Only users with full accounts can post comments. Log in, please.