Главная страница Взаимодействие нетривиальных процессов зом мы можем узнать, не будет ли им считан обратно только что записанный символ. При запуске этой программы в Solaris 2.6, в которой организована поддержка двусторонних каналов, мы получим ожидаемый результат: Solaris % fduplex child read p parent read с Символ p передается по одному из двух односторонних каналов, изображенных на рис. 4.10, а именно по верхнему каналу. Символ с передается по нижнему одностороннему каналу. Родительский процесс не считывает обратно записанный им в канал символ р (что и требуется). При запуске этой программы в Digital Unix 4,0В, в которой по умолчанию создаются односторонние каналы (двусторонние каналы - как в SVR4 - будут создаваться в том случае, если при компиляции указать специальные параметры), мы увидим результат, ожидаемый для одностороннего канала: alpha % fduplex read error: Bad file number alpha % child read p write error: Bad file number Родительский процесс записывает символ р, который успешно считывается дочерним процессом, однако при попытке считывания из канала (дескриптор fd[l]) родительский процесс прерывается с ошибкой, как и дочерний процесс, при попытке записи в канал (дескриптор fd[0]). Вспомните рис, 4.8, Функция read возвращает код ошибки EBADF, означающий, что дескриптор не открыт для чтения, Аядлотуппо wri te возвращает тот же код ошибки, если дескриптор не был открыт на запись, 4.5. Функции рореп и pclose Другим примером использования каналов является имеющаяся в стандартной библиотеке ввода-вывода функция рореп, которая создает канал и запускает другой процесс, записывающий данные в этот канал или считывающий их из него: #include <stdio.h> FILE *popen(const char *comand. const char Hype): I* Возвращает указатель FILE * в случае успешного выполнения, NULL - в случае ошибки */ int pcloseCFILE *streani): I* Возвращает код завершения команды интерпретатора или -1 - в случае ошибки */ Аргумент command представляет собой команду интерпретатора. Он обрабатывается программой sh (обычно это интерпретатор Bourne shell), поэтому для поиска исполняемого файла, вызываемого командой command, используется переменная PATH. Канал создается между вызывающим процессом и указанной командой. Возвращаемое функцией рореп значение представляет собой обычный указатель на тип FILE, который может использоваться для ввода или для вывода в зависимости от содержимого строки type: если type имеет значение г, вызывающий процесс считывает данные, направляемые командой command в стандартный поток вывода; если type имеет значение w, вызывающий процесс записывает данные в стандартный поток ввода команды command. Функция pclose закрывает стандартный поток ввода-вывода stream, созданный командой рореп, ждет завершения работы программы и возвращает код завершения, принимаемый от интерпретатора, ПРИМЕЧАНИЕ - Информацию о реализациях рореп и pclose можно найти в разделе 14.3 [21]. Пример в листинге 4.5 изображено еще одно решение задачи с клиентом и сервером, использующее функцию рореп и программу (утилиту Unix) cat. Листинг 4.5. Клиент-сервер с использованием рореп pipe/mainpopen.c 1 #include unpipc.h 2 int 3 mainCint argc. char **argv) 5 size t n: 6 char buff[MAXLINE]. command[MAXLINE]: 7 FILE *fp: 8 /* считывание полного имени */ 9 FgetsСbuff. MAXLINE. stdin): 10 n = strlenCbuff); /* fgetsC) гарантирует завершающий ноль */ 11 if Cbuff[n-1] -= Лп) 12 n--: /* удаление перевода строки из возврата fgetsC) */ 13 snprintfCcommand. sizeofСcommand). cat *s . buff); 14 fp - PopenCcommand, r ); 15 /* копирование из канала в стандартный вывод */ 16 while CFgetsCbuff, MAXLINE, fp) !- NULL) 17 FputsCbuff, stdout); 18 PcloseCfp): 19 exitCO): 20 } 8-17 Полное имя файла считывается из стандартного потока ввода, как и в программе в листинге 4,2, Формируется командная строка, которая передается рореп. Вывод интерпретатора команд или команды cat копируется в стандартный поток вывода. Одним из отличий этой реализации от приведенной в листинге 4.1 является отсутствие возможности формировать собственные сообщения об ошибках. Теперь мы целиком зависим от программы cat, а выводимые ею сообщения не всегда адекватны. Например, в системе Solaris 2.6 при попытке считать данные из файла, доступ на чтение к которому для нас запрещен, будет выведена следующая ошибка: Solaris % cat /etc/shadow cat: cannot open /etc/shadow А в BSD/OS 3.1 мы получим более информативное сообщение в аналогичной ситуации: bsdi % cat /etc/master.passwd cat: /etc/master.passwd: cannot open [Permission denied] Обратите также внимание на тот факт, что вызов рореп в данном случае оказывается успешным, однако при первом же вызове fgets будет возвращен символ конца файла (EOF). Программа cat записывает сообщение об ошибке в стандартный поток сообщений об ошибках (stderr), а рореп с этим потоком не связывается-к создаваемому каналу подключается только стандартный поток вывода. 4.6. Именованные каналы (FIFO) Программные каналы не имеют имен, и их главным недостатком является невозможность передачи информации между неродственными процессами. Два неродственных процесса не могут создать канал для связи между собой (если не передавать дескриптор). Аббревиатура FIFO расшифровывается как first in, first out - первым вошел, первым вышел , то есть эти каналы работают как очереди. Именованные каналы в Unix функционируют подобно неименованным - они позволяют передавать данные только в одну сторону. Однако в отличие от программных каналов каждому каналу FIFO сопоставляется полное имя в файловой системе, что позволяет двум неродственным процессам обратиться к одному и тому же FIFO. FIFO создается функцией mkf i f о: #include <sys/types.h> #include <sys/stat.h> int mkfifoCconst char *pathname. mode t mode): /* Возвращает 0 при успешном выполнении. -1 - при возникновении ошибок */ Здесь pathname - обычное для Unix полное имя файла, которое и будет именем FIFO. Аргумент mode указывает битовую маску разрешений доступа к файлу, аналогично второму аргументу команды open. В табл. 2.3 приведены шесть констант, определенных в заголовке <sys/stat. h>. Эти константы могут использоваться для задания разрешений доступа и к FIFO. Функция mkfifo действует как open, вызванная с аргументом 0 CREAT 0 EXCL. Это означает, что создается новый канал FIFO или возвращается ошибка EEXIST, в случае если канал с заданным полным именем уже существует. Если не требуется создавать новый канал, вызывайте open вместо mkf 1 fo. Для открытия существующего канала или создания нового в том случае, если его еще не существует, вызовите mkf i f о, проверьте, не возвращена ли ошибка ЕЕХ 1ST, и если такое случится, вызовите функцию open. Команда mkfi fo также создает канал FIFO. Ею можно пользоваться в сценариях интерпретатора или из командной строки. После создания канал FIFO должен быть открыт на чтение или запись с помощью либо функции open, либо одной из стандартных функций открытия файлов из библиотеки ввода-вывода (например, f open). FIFO может быть открыт либо только на чтение, либо только на запись. Нельзя открывать канал на чтение и запись, поскольку именованные каналы могут быть только односторонними.
|
© 2000 - 2024 ULTRASONEX-AMFODENT.RU.
Копирование материалов разрешено исключительно при условии цититирования. |