Главная страница  Взаимодействие нетривиальных процессов 

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 [ 19 ] 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186

зом мы можем узнать, не будет ли им считан обратно только что записанный символ.

При запуске этой программы в 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 может быть открыт либо только на чтение, либо только на запись. Нельзя открывать канал на чтение и запись, поскольку именованные каналы могут быть только односторонними.



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 [ 19 ] 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186

© 2000 - 2024 ULTRASONEX-AMFODENT.RU.
Копирование материалов разрешено исключительно при условии цититирования.