- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 19 века
- Недвижимость
- Музыка, музыканты
- Готические новеллы
- Истории из жизни
- Культура и искусство
- Спецслужбы
- Зарубежная прикладная литература
- Музыка, танцы
- Подростковая литература
- Прочее
- Военная техника, оружие
- Газеты и журналы
- Периодические издания
- Домоводство, Дом и семья
- Любовные романы
- Экономическая литература
- Научные и научно-популярные книги
- О животных
- Биохимия
- Культурология
- Юриспруденция
- Политика
- Психотерапия
- Языкознание
- Научпоп
- Медицина
- Психология, личное
- Радиотехника
- Филология
- Педагогика
- Образовательная литература
- Деловая литература
- Физика
- Науки: разное
- Химия
- Воспитание детей, педагогика
- Детская психология
- Зарубежная публицистика
- Биология
- Архитектура
- Зарубежная психология
- Науки о космосе
- Социология
- Математика
- География
- Беременность, ожидание детей
- Литературоведение
- Транспорт, военная техника
- Обществознание
- Зоология
- География
- Альтернативная медицина
- Иностранные языки
- Ветеринария
- Рефераты
- Астрология
- Биофизика
- Экология
- История Европы
- Учебники
- Шпаргалки
- Государство и право
- Ботаника
- Религиоведение
- История
- Техническая литература
- Прочая научная литература
- Психология
- Детективы и Триллеры
- Справочная литература
- Проза
- Новелла
- Юмор
- Проза
- Историческая проза
- Русская современная проза
- Советская классическая проза
- Повести
- Очерки
- Эссе
- Рассказы
- Зарубежная современная проза
- Сентиментальная проза
- Зарубежная классика
- Афоризмы
- Эпистолярная проза
- Феерия
- Семейный роман/Семейная сага
- Разное
- Антисоветская литература
- Магический реализм
- Русская классическая проза
- Современная проза
- О войне
- Контркультура
- Классическая проза
- Поэзия, Драматургия
- Детская литература
- Детская фантастика
- Детские остросюжетные
- Детские стихи
- Детские приключения
- Внеклассное чтение
- Учебная литература
- Зарубежные детские книги
- Бизнес
- Загадки
- Книги для подростков
- Школьные учебники
- Детский фольклор
- Книги для дошкольников
- Детские детективы
- Детская познавательная и развивающая литература
- Буквари
- Прочая детская литература
- Сказка
- Детская проза
- Детская образовательная литература
- Юмор
- Документальные книги
- Бизнес
- Внешнеэкономическая деятельность
- Тайм-менеджмент
- Кадровый менеджмент
- О бизнесе популярно
- Управление, подбор персонала
- Бизнес
- Менеджмент и кадры
- Продажи
- Экономика
- Ценные бумаги и инвестиции
- Малый бизнес
- Делопроизводство, офис
- Корпоративная культура, бизнес
- Банковское дело
- Финансы
- Зарубежная деловая литература
- Ораторское искусство / риторика
- Личные финансы
- Интернет-бизнес
- Поиск работы
- Государственное и муниципальное управление
- Бухучет и аудит
- Работа с клиентами
- Менеджмент
- Краткое содержание
- Личная эффективность
- Переговоры
- Приключения
- Старинная литература
- Религия и духовность
- Компьютеры и Интернет
- Блог
Читаем без скачивания UNIX: взаимодействие процессов - Уильям Стивенс
Шрифт:
Интервал:
Закладка:
Стандартная библиотека ввода-вывода также может использоваться для считывания и записи данных в пpoгрaммный канал или FIFO. Поскольку канал может быть открыт только функцией piре, возвращающей открытый дескриптор, для создания нового стандартного потока, связанного с этим дескриптором, можно использовать стандартную функцию fdopen. Канал FIFO обладает именем, поэтому он может быть открыт с помощью функции fopen.
Можно создавать и более структурированные сообщения — эта возможность предоставляется очередями сообщений и в Posix, и в System V. Мы вскоре узнаем, что каждое сообщение обладает длиной и приоритетом (типом в System V). Длина и приоритет указываются отправителем и возвращаются получателю после считывания сообщения. Каждое сообщение представляет собой запись, аналогично дeйтaгрaммaм UDP ([24]).
Мы можем структурировать данные, передаваемые по программному каналу или FIFO, самостоятельно. Определим сообщение в нашем заголовочном файле mesg.h, как показано в листинге 4.12.
Листинг 4.12. Структура mymesg и сопутствующие определения//pipemesg/mesg.h
1 #include "unpipc.h"
2 /* Наши собственные "сообщения", которые могут использоваться с каналами, FIFO и очередями сообщений */
3 /* Мы хотим, чтобы sizeof(struct mymesg) <= PIPE_BUF */
4 #define MAXMESGDATA (PIPE_BUF – 2*sizeof(long))
5 /* Длина mesg_len и mesg_type */
6 #define MESGHDRSIZE (sizeof(struct mymesg) – MAXMESGDATA)
7 struct mymesg {
8 long mesg_len; //количество байтов в mesg_data, может быть О
9 long mesg_type;//тип сообщения, должен быть > 0
10 char mesg_data[MAXMESGDATA];
11 };
12 ssize_t mesg_send(int, struct mymesg *);
13 void Mesg_send(int, struct mymesg *);
14 ssize_t mesg_recv(int, struct mymesg *);
15 ssize_t Mesg_recv(int, struct mymesg *);
Каждое сообщение содержит в себе информацию о своем типе (mesg_type), причем значение этой переменной должно быть больше нуля. Пока мы будем игнорировать это поле в записи, но вернемся к нему в главе 6, где описываются очереди сообщений System V. Каждое сообщение также обладает длиной, кoтopая может быть и нулевой. Структура mymesg позволяет предварить каждое сообщение информацией о его типе и длине вместо использования символа перевода строки для сигнализации конца сообщения. Ранее мы отметили два преимущества этого подхода: получатель не должен сканировать все принятые байты в поисках конца сообщения и отсутствует необходимость исключать появление разделителя в самих данных.
На рис. 4.13 изображен вид структуры mymesg и ее использование с каналами, FIFO и очередями сообщений System V.
Рис. 4.13. Структура mymesg
Мы определяем две функции для отправки и приема сообщений. В листинге 4.13 приведен текст функции mesg_send, а в листинге 4.14 — функции mesg_recv.
Листинг 4.13. Функция mesg_send//pipemesg/mesg_send.c
1 #include "mesg.h"
2 ssize_t
3 mesg_send(int fd, struct mymesg *mptr)
4 {
5 return(write(fd, mptr, MESGHDRSIZE + mptr->mesg_len));
6 }
Листинг 4.14. Функция mesg_recv//pipemesg/mesg_recv.c
1 #include "mesg.h"
2 ssize_t
3 mesg_recv(int fd, struct mymesg *mptr)
4 {
5 size_t len;
6 ssize_t n;
8 /* считывание заголовка сообщения для определения его длины */
9 if ((n = Read(fd, mptr, MESGHDRSIZE)) == 0)
10 return(0); /* end of file */
11 else if (n != MESGHDRSIZE)
12 err_quit("message header: expected %d, got %d". MESGHDRSIZE, n);
13 if ((len = mptr->mesg_len) > 0)
14 if ((n = Read(fd, mptr->mesg_data, len)) != len)
15 err_quit("message data: expected %d, got %d", len, n);
16 return(len);
17 }
Теперь для каждого сообщения функция read вызывается дважды: один раз для считывания длины, а другой — для считывания самого сообщения (если его длина больше 0).
ПРИМЕЧАНИЕ
Внимательные читатели могли заметить, что функция mesg_recv проверяет наличие всех возможных ошибок и прекращает работу при их обнаружении. Однако мы все же определили функцию-обертку Mesg_recv и вызываем из наших программ именно ее — для единообразия.
Изменим теперь функции client и server, чтобы воспользоваться новыми функциями mesg_send и mesg_recv. В листинге 4.15 приведен текст функции-клиента.
Листинг 4.15. Функция client с использованием сообщений//pipemesg/client.c
1 #include "mesg.h"
2 void
3 client(int readfd, int writefd)
4 {
5 size_t len;
6 ssize_t n;
7 struct mymesg mesg;
8 /* считывание полного имени */
9 Fgets(mesg.mesg_data, MAXMESGDATA, stdin);
10 len = strlen(mesg.mesg_data);
11 if (mesg.mesg_data[len-1] == 'n')
12 len--; /* удаление перевода строки из fgets() */
13 mesg.mesg_len = len;
14 mesg.mesg_type = 1;
15 /* запись полного имени в канал IPC */
16 Mesg_send(writefd, &mesg);
17 /* считывание из канала IPC. запись в stdout */
18 while ( (n = Mesg_recv(readfd, &mesg)) > 0)
19 Write(STDOUT_FILENO, mesg.mesg_data, n);
20 }
Считывание имени файла и отправка его серверу8-16 Полное имя считывается из стандартного потока ввода и затем отправляется на сервер с помощью функции mesg_send.
Считывание содержимого файла или сообщения об ошибке от сервера17-19 Клиент вызывает функцию mesg_recv в цикле, считывая все приходящие от сервера сообщения. По соглашению, когда mesg_recv возвращает нулевую длину сообщения, это означает конец передаваемых сервером данных. Мы увидим, что сервер добавляет символ перевода строки к каждому сообщению, отправляемому клиенту, поэтому пустая строка будет иметь длину сообщения 1. В листинге 4.16 приведен текст функции-сервера.
Листинг 4.16. Функция server, использующая сообщения//pipemesg/server.c
1 #include "mesg.h"
2 void
3 server(int readfd, int writefd)
4 {
5 FILE *fp;
6 ssize_t n;
7 struct mymesg mesg;
8 /* считывание полного имени из канала */
9 mesg.mesg_type = 1;
10 if ((n = Mesg_recv(readfd, &mesg)) == 0)
11 err_quit("pathname missing");
12 mesg.mesg_data[n] = ' '; /* полное имя, завершающееся 0 */
13 if ((fp = fopen(mesg.mesg_data, "r")) == NULL) {
14 /* ошибка, нужно сообщить клиенту */
15 snprintf(mesg.mesg_data + n, sizeof(mesg.mesg_data) – n,
16 ": can't open, %sn", strerror(errno));
17 mesg.mesg_len = strlen(mesg.mesg_data);
18 Mesg_send(writefd, &mesg);
19 } else {
20 /* файл успешно открыт, передача данных */
21 while (Fgets(mesg.mesg_data, MAXMESGDATA, fp) != NULL) {
22 mesg.mesg_len = strlen(mesg.mesg_data);
23 Mesg_send(writefd, &mesg);
24 }
25 Fclose(fp);
26 }
27 /* отправка сообщения нулевой длины для обозначения конца связи */
28 mesg.mesg_len = 0;
29 Mesg_send(writefd, &mesg);
30 }
Считывание имени файла из канала IPC, открытие файла8-18 Сервер принимает от клиента имя файла. Хотя значение mesg_type, равное 1, нигде не используется (оно затирается функцией mesg_recv из листинга 4.14), мы будем использовать ту же функцию при работе с очередями сообщений System V (листинг 6.8), а в данном случае в этом значении уже возникает потребность (см., например, листинг 6.11). Стандартная функция ввода-вывода fopen открывает файл, что отличается от листинга 4.3, где вызывалась функция open для получения дескриптора файла. Причина, по которой мы воспользовались fopen, заключается в том, что в этой пpoгрaммe мы пользуемся библиотечной функцией fgets для считывания содержимого файла построчно и затем отправляем клиенту строку за строкой.
Отправка файла клиенту19-26 Если вызов fopen оказывается успешным, содержимое файла считывается с помощью функции fgets и затем отправляется клиенту построчно. Сообщение с нулевой длиной означает конец файла.
При использовании пpoгрaммныx каналов или FIFO мы могли бы также закрыть канал IPC, чтобы дать клиенту знать о том, что передача файла завершена. Однако мы используем передачу сообщения нулевой длины, потому что другие типы IPC не поддерживают концепцию конца файла.
Функции main, вызывающие новые функции client и server, вообще не претерпели никаких изменений. Мы можем использовать либо версию для работы с каналами (листинг 4.1), либо версию для работы с FIFO (листинг 4.6).
4.11. Ограничения программных каналов и FIFO
На программные каналы и каналы FIFO системой накладываются всего два ограничения:
■ OPEN_MAX — максимальное количество дескрипторов, которые могут быть одновременно открыты некоторым процессом (Posix устанавливает для этой величины ограничение снизу — 16);
■ PIPE_BUF — максимальное количество данных, для которого гарантируется атомарность операции записи (описано в разделе 4.7; Posix требует по меньшей мере 512 байт).