- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 19 века
- Недвижимость
- Музыка, музыканты
- Готические новеллы
- Истории из жизни
- Культура и искусство
- Спецслужбы
- Зарубежная прикладная литература
- Музыка, танцы
- Подростковая литература
- Прочее
- Военная техника, оружие
- Газеты и журналы
- Периодические издания
- Домоводство, Дом и семья
- Любовные романы
- Экономическая литература
- Научные и научно-популярные книги
- О животных
- Биохимия
- Культурология
- Юриспруденция
- Политика
- Психотерапия
- Языкознание
- Научпоп
- Медицина
- Психология, личное
- Радиотехника
- Филология
- Педагогика
- Образовательная литература
- Деловая литература
- Физика
- Науки: разное
- Химия
- Воспитание детей, педагогика
- Детская психология
- Зарубежная публицистика
- Биология
- Архитектура
- Зарубежная психология
- Науки о космосе
- Социология
- Математика
- География
- Беременность, ожидание детей
- Литературоведение
- Транспорт, военная техника
- Обществознание
- Зоология
- География
- Альтернативная медицина
- Иностранные языки
- Ветеринария
- Рефераты
- Астрология
- Биофизика
- Экология
- История Европы
- Учебники
- Шпаргалки
- Государство и право
- Ботаника
- Религиоведение
- История
- Техническая литература
- Прочая научная литература
- Психология
- Детективы и Триллеры
- Справочная литература
- Проза
- Новелла
- Юмор
- Проза
- Историческая проза
- Русская современная проза
- Советская классическая проза
- Повести
- Очерки
- Эссе
- Рассказы
- Зарубежная современная проза
- Сентиментальная проза
- Зарубежная классика
- Афоризмы
- Эпистолярная проза
- Феерия
- Семейный роман/Семейная сага
- Разное
- Антисоветская литература
- Магический реализм
- Русская классическая проза
- Современная проза
- О войне
- Контркультура
- Классическая проза
- Поэзия, Драматургия
- Детская литература
- Детская фантастика
- Детские остросюжетные
- Детские стихи
- Детские приключения
- Внеклассное чтение
- Учебная литература
- Зарубежные детские книги
- Бизнес
- Загадки
- Книги для подростков
- Школьные учебники
- Детский фольклор
- Книги для дошкольников
- Детские детективы
- Детская познавательная и развивающая литература
- Буквари
- Прочая детская литература
- Сказка
- Детская проза
- Детская образовательная литература
- Юмор
- Документальные книги
- Бизнес
- Внешнеэкономическая деятельность
- Тайм-менеджмент
- Кадровый менеджмент
- О бизнесе популярно
- Управление, подбор персонала
- Бизнес
- Менеджмент и кадры
- Продажи
- Экономика
- Ценные бумаги и инвестиции
- Малый бизнес
- Делопроизводство, офис
- Корпоративная культура, бизнес
- Банковское дело
- Финансы
- Зарубежная деловая литература
- Ораторское искусство / риторика
- Личные финансы
- Интернет-бизнес
- Поиск работы
- Государственное и муниципальное управление
- Бухучет и аудит
- Работа с клиентами
- Менеджмент
- Краткое содержание
- Личная эффективность
- Переговоры
- Приключения
- Старинная литература
- Религия и духовность
- Компьютеры и Интернет
- Блог
Читаем без скачивания UNIX: взаимодействие процессов - Уильям Стивенс
Шрифт:
Интервал:
Закладка:
Двусторонний канал мог бы быть реализован так, как это изображено на рис. 4.9. В этом случае неявно предполагается существование единственного буфера, в который помещается все, что записывается в канал (с любого конца, то есть дескриптора), и при чтении из канала данные просто считываются из буфера.
Рис. 4.9. Одна из возможных реализаций двустороннего канала (неправильная)
Такая реализация вызовет проблемы, например, в программе листинга А.14. Здесь требуется двусторонняя передача информации, причем потоки данных должны быть независимы. В противном случае некоторый процесс, записав данные в канал и перейдя затем в режим чтения из этого же канала, рискует считать обратно те же данные, которые были им только что туда записаны.
На рис. 4.10 изображена правильная реализация двустороннего канала.
Рис. 4.10. Правильная реализация двустороннего канала
Здесь двусторонний канал получается из объединения двух односторонних. Все данные, записываемые в fd[1], будут доступны для чтения из fd[0], а данные, записываемые в fd[0], будут доступны для чтения из fd[1].
Программа в листинге 4.4 иллюстрирует использование одного двустороннего канала для двусторонней передачи информации.
Листинг 4.4. Двусторонняя связь через двусторонний канал//pipe/fduplex.c
1 #include "unpipc.h"
2 int
3 main(int argc, char **argv)
4 {
5 int fd[2], n;
6 char c;
7 pid_t childpid;
8 Pipe(fd); /* предполагается двусторонний канал (напр., SVR4) */
9 if ((childpid = Fork()) == 0) { /* child */
10 sleep(3):
11 if ((n = Read(fd[0], &c, 1)) != 1)
12 err_quit("child: read returned %d", n);
13 printf("child read %cn", c):
14 Write(fd[0], "c", 1);
15 exit(0);
16 }
17 /* родитель */
18 Write(fd[1], "p", 1);
19 if ((n = Read(fd[1], &c, 1)) != 1)
20 err_quit("parent: read returned %d", n):
21 printf("parent read %cn", c);
22 exit(0);
23 }
В этой программе сначала создается двусторонний канал, затем делается системный вызов fork. Породивший процесс записывает символ р в канал, а затем считывает из канала данные. Дочерний процесс ждет три секунды, считывает символ из канала, а потом записывает туда символ с. Задержка чтения для дочернего процесса позволяет породившему процессу вызвать read первым — таким образом мы можем узнать, не будет ли им считан обратно только что записанный символ.
При запуске этой программы в Solaris 2.6, в которой организована поддержка двусторонних каналов, мы получим ожидаемый результат:
solaris % fduplex
child read p
parent read с
Символ р передается по одному из двух односторонних каналов, изображенных на рис. 4.10, а именно по верхнему каналу. Символ с передается по нижнему одностороннему каналу. Родительский процесс не считывает обратно записанный им в канал символ р (что и требуется).
При запуске этой программы в Digital Unix 4.0B, в которой по умолчанию создаются односторонние каналы (двусторонние каналы — как в 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, означающий, что дескриптор не открыт для чтения. Аналогично write возвращает тот же код ошибки, если дескриптор не был открыт на запись.
4.5. Функции popen и pclose
Другим примером использования каналов является имеющаяся в стандартной библиотеке ввода-вывода функция popen, которая создает канал и запускает другой процесс, записывающий данные в этот канал или считывающий их из него:
#include <stdio.h>
FILE *popen(const char *соmmаnd, const char *tуре);
/* Возвращает указатель FILE * в случае успешного выполнения, NULL – в случае ошибки */
int pclose(FILE *strеаm);
/* Возвращает код завершения команды интерпретатора или –1 – в случае ошибки */
Аргумент command представляет собой команду интерпретатора. Он обрабатывается программой sh (обычно это интерпретатор Bourne shell), поэтому для поиска исполняемого файла, вызываемого командой command, используется переменная PATH. Канал создается между вызывающим процессом и указанной командой. Возвращаемое функцией popen значение представляет собой обычный указатель на тип FILE, который может использоваться для ввода или для вывода в зависимости от содержимого строки type:
■ если type имеет значение r, вызывающий процесс считывает данные, направляемые командой command в стандартный поток вывода;
■ если type имеет значение w, вызывающий процесс записывает данные в стандартный поток ввода команды command.
Функция pclose закрывает стандартный поток ввода-вывода stream, созданный командой popen, ждет завершения работы программы и возвращает код завершения, принимаемый от интерпретатора.
ПРИМЕЧАНИЕ
Информацию о реализациях popen и pclose можно найти в разделе 14.3 [21].
Пример
В листинге 4.5 изображено еще одно решение задачи с клиентом и сервером, использующее функцию popen и программу (утилиту Unix) cat.
Листинг 4.5. Клиент-сервер с использованием popen//pipe/mainpopen.c
1 #include "unpipc.h"
2 int
3 main(int argc, char **argv)
4 {
5 size_t n;
6 char buff[MAXLINE], command[MAXLINE];
7 FILE *fp;
8 /* считывание полного имени */
9 Fgets(buff, MAXLINE, stdin);
10 n = strlen(buff); /* fgets() гарантирует завершающий ноль */
11 if (buff[n-1] == 'n')
12 n--; /* удаление перевода строки из возврата fgets() */
13 snprintf(command, sizeof(command), "cat %s", buff);
14 fp = Popen(command, "r");
15 /* копирование из канала в стандартный вывод */
16 while(Fgets(buff, MAXLINE, fp) != NULL)
17 Fputs(buff, stdout);
18 Pclose(fp);
19 exit(0);
20 }
8-17 Полное имя файла считывается из стандартного потока ввода, как и в программе в листинге 4.2. Формируется командная строка, которая передается popen. Вывод интерпретатора команд или команды 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]
Обратите также внимание на тот факт, что вызов popen в данном случае оказывается успешным, однако при первом же вызове fgets будет возвращен символ конца файла (EOF). Программа cat записывает сообщение об ошибке в стандартный поток сообщений об ошибках (stderr), а popen с этим потоком не связывается — к создаваемому каналу подключается только стандартный поток вывода.
4.6. Именованные каналы (FIFO)
Программные каналы не имеют имен, и их главным недостатком является невозможность передачи информации между неродственными процессами. Два неродственных процесса не могут создать канал для связи между собой (если не передавать дескриптор).
Аббревиатура FIFO расшифровывается как «first in, first out» — «первым вошел, первым вышел», то есть эти каналы работают как очереди. Именованные каналы в Unix функционируют подобно неименованным — они позволяют передавать данные только в одну сторону. Однако в отличие от программных каналов каждому каналу FIFO сопоставляется полное имя в файловой системе, что позволяет двум неродственным процессам обратиться к одному и тому же FIFO.
FIFO создается функцией mkfifо:
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *раthnаme, mode_t mоdе);
/* Возвращает 0 при успешном выполнении, –1 – при возникновении ошибок */