Unix - статьи



         

Неименованные каналы - часть 2


Эта операция очень похожа на открытие обычного файла для чтения. Переменная f имеет тип FILE *, но в параметре argv[1] функции popen передается не имя файла, а команда на запуск программы или команды оболочки, например, "ls -al". Если вызов popen() был успешен, мы можем считывать данные, выводимые запущенной командой, с помощью обычной функции fread(3): fread(buf, 1, BUF_SIZE, f)

Особенность функции popen() заключается в том, что эта функция не возвращает NULL, даже если переданная ей команда не является корректной. Самый простой способ обнаружить ошибку в этой ситуации - попытаться прочесть данные из потока вывода. Если в потоке вывода нет данных (fread() возвращает значение 0), значит произошла ошибка. Для вывода данных, прочитанных с помощью fread(), на терминал мы используем функцию write() с указанием дескриптора стандартного потока вывода: write(1, buf, len);

Параллельно эти же данные записываются в файл на диске. По окончании чтения данных открытый канал нужно закрыть: pclose(f);

Следует иметь в виду, что pclose() вернет управление вызывающему потоку только после того как запущенное с помощью popen() приложение завершит свою работу.

В заключение отметим еще одну особенность функции popen(). Для выполнения переданной ей команды popen() сперва запускает собственный экземпляр оболочки, что с одной стороны хорошо, а с другой - не очень. Хорошо это потому, что при вызове popen() автоматически выполняются внутренние операции оболочки (такие как обработка шаблонов имен файлов), используются переменные окружения типа PATH и HOME и т.п. Отрицательная сторона подхода, применяемого popen(), связана с дополнительными накладными расходы на запуск процесса оболочки в том случае, когда для выполнения команды оболочка не нужна.

Для обмена данными с внешним приложением функция popen() использует каналы неявным образом. В своих программах мы можем использовать каналы и непосредственно. Наиболее распространенный тип каналов, - неименованные однонаправленные каналы (anonymous pipes), создаваемые функцией pipe(2). На уровне интерфейса программирования такой канал представляется двумя дескрипторами файлов, один из которых служит для чтения данных, а другой - для записи. Каналы не поддерживают произвольный доступ, т. е. данные могут считываться только в том же порядке, в котором они записывались. Неименованные каналы используются преимущественно вместе с функцией fork(2) и служат для обмена данными между родительским и дочерним процессами. Для организации подобного обмена данными, сначала, с помощью функции pipe(), создается канал. Функции pipe() передается единственный параметр - массив типа int, состоящий из двух элементов. В первом элементе массива функция возвращает дескриптор файла, служащий для чтения данных из канала (выход канала), а во втором - дескриптор для записи (вход). Затем, с помощью функции fork() процесс «раздваивается». Дочерний процесс наследует от родительского процесса оба дескриптора, открытых с помощью pipe(), но, также как и родительский процесс, он должен использовать только один из дескрипторов. Направление передачи данных между родительским и дочерним процессом определяется тем, какой дескриптор будет использоваться родительским процессом, а какой - дочерним. Продемонстрируем изложенное на простом примере программы pipes.c, использующей функции pipe() и fork().




Содержание  Назад  Вперед