- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 19 века
- Недвижимость
- Музыка, музыканты
- Готические новеллы
- Истории из жизни
- Культура и искусство
- Спецслужбы
- Зарубежная прикладная литература
- Музыка, танцы
- Подростковая литература
- Прочее
- Военная техника, оружие
- Газеты и журналы
- Периодические издания
- Домоводство, Дом и семья
- Любовные романы
- Экономическая литература
- Научные и научно-популярные книги
- О животных
- Биохимия
- Культурология
- Юриспруденция
- Политика
- Психотерапия
- Языкознание
- Научпоп
- Медицина
- Психология, личное
- Радиотехника
- Филология
- Педагогика
- Образовательная литература
- Деловая литература
- Физика
- Науки: разное
- Химия
- Воспитание детей, педагогика
- Детская психология
- Зарубежная публицистика
- Биология
- Архитектура
- Зарубежная психология
- Науки о космосе
- Социология
- Математика
- География
- Беременность, ожидание детей
- Литературоведение
- Транспорт, военная техника
- Обществознание
- Зоология
- География
- Альтернативная медицина
- Иностранные языки
- Ветеринария
- Рефераты
- Астрология
- Биофизика
- Экология
- История Европы
- Учебники
- Шпаргалки
- Государство и право
- Ботаника
- Религиоведение
- История
- Техническая литература
- Прочая научная литература
- Психология
- Детективы и Триллеры
- Справочная литература
- Проза
- Новелла
- Юмор
- Проза
- Историческая проза
- Русская современная проза
- Советская классическая проза
- Повести
- Очерки
- Эссе
- Рассказы
- Зарубежная современная проза
- Сентиментальная проза
- Зарубежная классика
- Афоризмы
- Эпистолярная проза
- Феерия
- Семейный роман/Семейная сага
- Разное
- Антисоветская литература
- Магический реализм
- Русская классическая проза
- Современная проза
- О войне
- Контркультура
- Классическая проза
- Поэзия, Драматургия
- Детская литература
- Детская фантастика
- Детские остросюжетные
- Детские стихи
- Детские приключения
- Внеклассное чтение
- Учебная литература
- Зарубежные детские книги
- Бизнес
- Загадки
- Книги для подростков
- Школьные учебники
- Детский фольклор
- Книги для дошкольников
- Детские детективы
- Детская познавательная и развивающая литература
- Буквари
- Прочая детская литература
- Сказка
- Детская проза
- Детская образовательная литература
- Юмор
- Документальные книги
- Бизнес
- Внешнеэкономическая деятельность
- Тайм-менеджмент
- Кадровый менеджмент
- О бизнесе популярно
- Управление, подбор персонала
- Бизнес
- Менеджмент и кадры
- Продажи
- Экономика
- Ценные бумаги и инвестиции
- Малый бизнес
- Делопроизводство, офис
- Корпоративная культура, бизнес
- Банковское дело
- Финансы
- Зарубежная деловая литература
- Ораторское искусство / риторика
- Личные финансы
- Интернет-бизнес
- Поиск работы
- Государственное и муниципальное управление
- Бухучет и аудит
- Работа с клиентами
- Менеджмент
- Краткое содержание
- Личная эффективность
- Переговоры
- Приключения
- Старинная литература
- Религия и духовность
- Компьютеры и Интернет
- Блог
Читаем без скачивания UNIX: взаимодействие процессов - Уильям Стивенс
Шрифт:
Интервал:
Закладка:
1-6 Мы определяем две структуры — одну для аргументов (одно поле типа long) и одну для результатов (тоже одно поле типа long).
Определение программы, версии и процедуры7-11 Мы определяем программу RPC с именем SQUARE_PROG, состоящую из одной версии (SQUARE_VERS), а эта версия представляет собой единственную процедуру сервера с именем SQUAREPROC. Аргументом этой процедуры является структура square_in, а возвращаемым значением — структура square_out. Мы также присваиваем этой процедуре номер 1, как и версии, а программе мы присваиваем 32-разрядный шестнадцатеричный номер. (О номерах программ более подробно говорится в табл. 16.1.)
Компилировать спецификацию нужно программой rpcgen, входящей в пакет Sun RPC.
Теперь напишем функцию main клиента, который будет осуществлять удаленный вызов процедуры. Текст программы приведен в листинге 16.2.
Листинг 16.2. Функция main клиента, делающего удаленный вызов процедуры//sunrpc/square1/client.c
1 #include "unpipc.h" /* наш заголовочный файл */
2 #include "square.h" /* создается rpcgen */
3 int
4 main(int argc, char **argv)
5 {
6 CLIENT *cl;
7 square_in in;
8 square_out *outp;
9 if (argc != 3)
10 err_quit("usage: client <hostname> <integer-value>");
11 cl = Clnt_create(argv[1], SQUARE_PROG, SQUARE_VERS, "tcp");
12 in.arg1 = atol(argv[2]);
13 if ((outp = squareproc_1(&in, cl)) == NULL)
14 err_quit("ls", clnt_sperror(cl, argv[1]));
15 printf("result: %ldn", outp->res1);
16 exit(0);
17 }
Подключение заголовочного файла, создаваемого rpcgen2 Мы подключаем заголовочный файл square.h, создаваемый функцией rpcgen.
Объявление дескриптора клиента6 Мы объявляем дескриптор клиента (client handle) с именем cl. Дескрипторы клиентов выглядят как обычные указатели на тип FILE (поэтому слово CLIENT пишется заглавными буквами).
Получение дескриптора клиента11 Мы вызываем функцию clnt_create, создающую клиент RPC:
#include <rpc/rpc.h>
CLIENT *clnt_create(const char *host, unsigned long prognum, unsigned long versnum, const char *protocol);
/* Возвращает ненулевой дескриптор клиента в случае успешного завершения. NULL – в случае ошибки */
Как и с обычными указателями на тип FILE, нам безразлично, на что указывает дескриптор клиента. Скорее всего, это некоторая информационная структура, хранящаяся в ядре. Функция clnt_create создает такую структуру и возвращает нам указатель на нее, а мы передаем его библиотеке RPC времени выполнения каждый раз при удаленном вызове процедуры.
Первым аргументом clnt_create должно быть имя или IP-адрес узла, на котором выполняется сервер. Вторым аргументом будет имя программы, третьим — номер версии. Оба эти значения берутся из спецификации (square.х, листинг 16.1). Последний аргумент позволяет указать протокол, обычно TCP или UDP.
Вызов удаленной процедуры и вывод результата12-15 Мы вызываем процедуру, причем первый аргумент указывает на входную структуру (&in), а второй содержит дескриптор клиента. В большинстве стандартных функций ввода-вывода дескриптор файла является последним аргументом. Точно так же и в вызовах RPC дескриптор клиента передается последним. Возвращаемое значение представляет собой указатель на структуру, в которой хранится результат работы сервера. Место под входную структуру выделяет программист, а под возвращаемую — пакет RPC.
В файле спецификации square.x мы назвали процедуру SQUAREPROC, но из клиента мы вызываем squareproc_1. Существует соглашение о преобразовании имени из файла спецификации к нижнему регистру и добавлении номера версии через символ подчеркивания.
Со стороны сервера от нас требуется только написать процедуру. Функция main автоматически создается программой rpcgen. Текст процедуры приведен в листинге 16.3.
Листинг 16.3. Процедура сервера, вызываемая с помощью Sun RPC//sunrpc/square1/server.c
1 #include "unpipc.h"
2 #include "square.h"
3 square_out *
4 squareproc_l_svc(square_in *inp, struct svc_req *rqstp)
5 {
6 static square_out out;
7 out.res1 = inp->arg1 * inp->arg1;
8 return(&out);
9 }
Аргументы процедуры3-4 Прежде всего мы замечаем, что к имени процедуры добавился суффикс _svc. Это дает возможность использовать два прототипа функций ANSI С в файле square.x, один из которых определяет функцию, вызываемую клиентом в листинге 16.2 (она принимает дескриптор клиента), а второй — реальную функцию сервера (которая принимает другие аргументы).
При вызове процедуры сервера первый аргумент является указателем на входную структуру, а второй — на структуру, передаваемую библиотекой RPC времени выполнения, которая содержит информацию о данном вызове (в этом примере игнорируется для простоты).
Выполнение и возврат6-8 Программа считывает входной аргумент и возводит его в квадрат. Результат сохраняется в структуре, адрес которой возвращается процедурой сервера. Поскольку мы возвращаем адрес переменной, эта переменная не может быть автоматической. Мы объявляем ее как статическую (static).
ПРИМЕЧАНИЕ
Внимательные читатели заметят, что это лишает нашу функцию возможности использования в защищенном поточном программировании. Мы обсудим это в разделе 16.2, где приведем пример защищенной функции.
Откомпилируем клиент в системе Solaris, а сервер — в BSD/OS, запустим сервер, а затем клиент:
solaris % client bsdi 11
result: 121
solaris % client 209.75.135.35 22
result: 484
В первом случае мы указываем имя узла сервера, а во втором — его IP-адрес. Этим мы демонстрируем возможность использования как имен, так и IP-адресов для задания узла в функции clnt_create.
Теперь продемонстрируем некоторые ошибки, возникающие при работе clnt_create, если, например, не существует узел или на нем не запущена программа-сервер:
solaris % client nosuchhost 11
nosuchhost: RPC: Unknown host возвращается библиотекой RPC времени выполнения
clnt_create error возвращается нашей функцией-оберткой
solaris % client localhost 11
localhost: rpc: program not registered
clnt_create error
Мы написали клиентскую и серверную части программы и продемонстрировали их использование вообще без явного сетевого программирования. Клиент просто вызывает две функции, а сервер вообще состоит из одной функции. Все тонкости использования XTI в Solaris, сокетов в BSD/OS и сетевого ввода-вывода обрабатываются библиотекой RPC времени выполнения. В этом и состоит предназначение RPC — предоставлять возможность создания распределенных приложений без знания сетевого программирования.
Другая немаловажная деталь данного примера заключается в том, что в системах Sparc под Solaris и Intel x86 под управлением BSD/OS используется разный порядок байтов. В Sparc используется порядок big endian («тупоконечный»[2]), а в Intel — little endian («остроконечный») (что мы показали в разделе 3.4 [24]). Отличия в порядке байтов также обрабатываются библиотекой RPC времени выполнения автоматически с использованием стандарта XDR (внешнее представление данных), который мы обсудим в разделе 16.8.
Создание программы-клиента и программы-сервера в данном случае требует больше операций, чем для любой другой программы этой книги. Выполняемый файл клиента получается следующим образом:
solaris % rpcgen-Сsquare.x
solaris % cc-сclient.с-оclient.о
solaris % cc-сsquare_clnt.c-оsquare_clnt.o
solaris % cc-сsquare_xdr.с-оsquare_xdr.o
solaris % cc-оclient client.оsquare_clnt.o square_xdr.o libunpipc.a –lnsl
Параметр –С говорит rpcgen о необходимости создания прототипов функций ANSI С в заголовочном файле square.h. Программа rpcgen также создает заглушку клиента (client stub) в файле с именем square_clnt.с и файл с именем square_xdr.с, который осуществляет преобразование данных в соответствии со стандартом XDR. Наша библиотека (содержащая функции, используемые в этой книге) называется libunpipc.a, а параметр –lnsl подключает системную библиотеку сетевых функций в Solaris (включая библиотеки RPC и XDR времени выполнения).
Аналогичные команды используются для создания сервера, хотя rpcgen уже не нужно запускать снова. Файл square_svc.c содержит функцию main сервера, и файл square_xdr.о, обсуждавшийся выше, также требуется для работы сервера:
solaris % cc –с server.с –о server.о
solaris % сc –с square_svc.c –о square_svc.o
solaris % cc –о server server.о square_svc.o libunpipc.a –lnsl
При этом создаются клиент и сервер, выполняемые в системе Solaris.
Если клиент и сервер должны быть построены для разных систем (как в предыдущем примере, где клиент выполнялся в Solaris, а сервер — в BSD/OS), могут потребоваться дополнительные действия. Например, некоторые файлы должны быть либо общими (через NFS), либо находиться в обеих системах, а файлы, используемые клиентом и сервером (например, square_xdr.o), должны компилироваться в каждой системе в отдельности.