Читать книгу 📗 "Операционная система UNIX - Робачевский Андрей Михайлович"
result = 0; close(fd); return(&result); /* Возвращаем результат — адрес result */}Заглушка клиента принимает аргумент, передаваемый удаленной процедуре, делает необходимые преобразования, формирует запрос на сервер portmap(1M), обменивается данными с сервером удаленной процедуры и, наконец, передает возвращаемое значение клиенту. Для клиента вызов удаленной процедуры сводится к вызову заглушки и ничем не отличается от обычного локального вызова.
#include <rpc/rpc.h>#include "log.h"main(int argc, char* argv[]) { CLIENT *cl; char *server, *mystring, *clnttime; time_t bintime; int* result; if (argc != 2) { fprintf(stderr, "Формат вызова: %s Адрес_хостаn", argv[0]); exit(1); } server = argv[1]; /* Получим дескриптор клиента. В случае неудачи — сообщим о невозможности установления связи с сервером */ if ((cl = clnt_create(server, LOG_PROG, LOG_VER, "udp")) == NULL) { clnt_pcreateerror(server); exit(2); } /* Выделим буфер для строки */ mystring = (char*)malloc(100); /* Определим время события */ bintime = time((time_t*)NULL); clnttime = ctime(&bintime); sprintf(mystring, "%s - Клиент запущен", clntime); /* Передадим сообщение для журнала — время начала работы клиента. В случае неудачи — сообщим об ошибке */ if ((result = rlog_1(&mystring, cl)) == NULL) { fprintf(stderr, "error2n"); clnt_perror(cl, server); exit(3); } /* В случае неудачи на удаленном компьютере сообщим об ошибке */ if (*result != 0) fprintf(stderr, "Ошибка записи в журналn"); /* Освободим дескриптор */ clnt_destroy(cl); exit(0);}Заглушка клиента log_clnt.с компилируется с модулем client.с для получения исполняемой программы клиента.
cc -o rlog client.c log_clnt.c -lns1Заглушка сервера log_svc.с и процедура log.c компилируются для получения исполняемой программы сервера.
cc -o logger log_svc.c log.c -lns1Теперь на некотором хосте server.nowhere.ru необходимо запустить серверный процесс:
$ <b>logger</b>После чего при запуске клиента rlog на другой машине сервер добавит соответствующую запись в файл журнала.
Схема работы RPC в этом случае приведена на рис. 6.20. Модули взаимодействуют следующим образом:
1. Когда запускается серверный процесс, он создает сокет UDP и связывает любой локальный порт с этим сокетом. Далее сервер вызывает библиотечную функцию svc_register(3N) для регистрации номеров программы и ее версии. Для этого функция обращается к процессу portmap(1M) и передает требуемые значения. Сервер portmap(1M) обычно запускается при инициализации системы и связывается с некоторым общеизвестным портом. Теперь portmap(3N) знает номер порта для нашей программы и версии. Сервер же ожидает получения запроса. Заметим, что все описанные действия производятся заглушкой сервера, созданной компилятором rpcgen(1M).
2. Когда запускается программа rlog, первое, что она делает, — вызывает библиотечную функцию clnt_create(3N), указывая ей адрес удаленной системы, номера программы и версии, а также транспортный протокол. Функция направляет запрос к серверу portmap(1M) удаленной системы server.nowhere.ru и получает номер удаленного порта для сервера журнала.
3. Клиент вызывает процедуру
rlog_1()rlog_1()rlog_1()
Рис. 6.20. Работа системы RPC
Поддержка сети в BSD UNIX
Перейдем теперь к обсуждению внутренней архитектуры сетевого в UNIX. Разговор начнем с ветви UNIX, в которой реализация TCP/IP появилась впервые — BSD UNIX.
Сетевая подсистема UNIX может быть представлена состоящей из трех уровней, каждый из которых отвечает за выполнение определенных функций:
| Транспортный уровень | Обмен данными между процессами |
| Сетевой уровень | Маршрутизация сообщений |
| Уровень сетевого интерфейса | Передача данных по физической сети |
Два верхних уровня представляют собой модули коммуникационных протоколов, а нижний уровень по существу является драйвером устройства. Легко заметить, что представленные уровни соответствуют транспортному, сетевому уровням и уровню канала данных модели OSI.