Рейтинговые книги
Читем онлайн Операционная система UNIX - Андрей Робачевский

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 108 109 110 111 112 113 114 115 116 ... 130

#define LOG_VER  ((unsigned long)(1)) /* Номер версии */

#define RLOG     ((unsigned long)(1)) /* Номер процедуры */

extern int *rlog_1();

/* Внутренняя процедура - нам ее использовать не придется */

extern int log_prog_1_freeresult();

#endif /* !_LOG_H_RPCGEN */

Рассмотрим этот файл внимательно. Компилятор транслирует имя RLOG, определенное в файле описания интерфейса, в rlog_1, заменяя прописные символы на строчные и добавляя номер версии программы с подчеркиванием. Тип возвращаемого значения изменился с int на int*. Таково правило — RPC позволяет передавать и получать только адреса объявленных при описании интерфейса параметров. Это же правило касается и передаваемой в качестве аргумента строки. Хотя из файла print.h это не следует, на самом деле в качестве аргумента функции rlog_1() также передается адрес строки.

Помимо файла заголовков компилятор rpcgen(1) создает модули заглушки клиента и заглушки сервера. По существу, в тексте этих файлов заключен весь код удаленного вызова.

Заглушка сервера является головной программой, обрабатывающей все сетевое взаимодействие с клиентом (точнее, с его заглушкой). Для выполнения операции заглушка сервера производит локальный вызов функции, текст которой необходимо написать:

log.с

#include <rpc/rpc.h>

#include <sys/types.h>

#include <sys/stat.h>

#include "log.h"

int* rlog_1(char** arg) {

 /* Возвращаемое значение должно определяться как static */

 static int result;

 int fd; /* Файловый дескриптор журнала */

 int len;

 result = 1;

 /* Откроем файл журнала (создадим, если он не существует),

    в случае неудачи вернем код ошибки result == 1. */

 if ((fd = open("./server.log",

  O_CREAT | O_RDWR | O_APPEND)) < 0)

  return(&result);

 len = strlen(*arg);

 if (write(fd, arg, strlen(arg) != len)

  result = 1;

 else

  result = 0;

 close(fd);

 return(&result); /* Возвращаем результат — адрес result */

}

Заглушка клиента принимает аргумент, передаваемый удаленной процедуре, делает необходимые преобразования, формирует запрос на сервер portmap(1M), обменивается данными с сервером удаленной процедуры и, наконец, передает возвращаемое значение клиенту. Для клиента вызов удаленной процедуры сводится к вызову заглушки и ничем не отличается от обычного локального вызова.

client.c

#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 необходимо запустить серверный процесс:

$ logger

После чего при запуске клиента 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(), определенную в заглушке клиента, и передает управление заглушке. Та, в свою очередь, формирует запрос (преобразуя аргументы в формат XDR) в виде пакета UDP и направляет его на удаленный порт, полученный от сервера portmap(1M). Затем она некоторое время ожидает отклика и в случае неполучения повторно отправляет запрос. При благоприятных обстоятельствах запрос принимается сервером logger (модулем заглушки сервера). Заглушка определяет, какая именно функция была вызвана (по номеру процедуры), и вызывает функцию rlog_1() модуля log.c. После возврата управления обратно в заглушку преобразует возвращенное функцией rlog_1() значение в формат XDR, и формирует отклик также в виде пакета UDP. После получения отклика заглушка клиента извлекает возвращенное значение, преобразует его и возвращает в головную программу клиента.

Рис. 6.20. Работа системы RPC

Поддержка сети в BSD UNIX

Перейдем теперь к обсуждению внутренней архитектуры сетевого в UNIX. Разговор начнем с ветви UNIX, в которой реализация TCP/IP появилась впервые — BSD UNIX.

Сетевая подсистема UNIX может быть представлена состоящей из трех уровней, каждый из которых отвечает за выполнение определенных функций:

Транспортный уровень Обмен данными между процессами Сетевой уровень Маршрутизация сообщений Уровень сетевого интерфейса Передача данных по физической сети

Два верхних уровня представляют собой модули коммуникационных протоколов, а нижний уровень по существу является драйвером устройства. Легко заметить, что представленные уровни соответствуют транспортному, сетевому уровням и уровню канала данных модели OSI.

Транспортный уровень является самым верхним в системе и призван обеспечить необходимую адресацию и требуемые характеристики передачи данных, определенных коммуникационным узлом процесса, которым является сокет. Например, сокет потока предполагает надежную последовательную доставку данных, и в семействе TCP/IP модуль данного уровня реализует протокол TCP. Следующий, сетевой, уровень обеспечивает передачу данных, адресованных удаленному сетевому или транспортному модулю. Для этого модуль данного уровня должен иметь доступ к информации о маршрутах сети (таблице маршрутизации). Наконец, последний уровень отвечает за передачу данных хостам, подключенным к одной физической среде передачи (например, находящимся в одном сегменте Ethernet).

Внутренняя структура сетевой подсистемы изолирована от непосредственного доступа прикладных процессов. Единым (и единственным) интерфейсом доступа к сетевым услугам является интерфейс сокетов, рассмотренный в главе 3 в разделе "Межпроцессное взаимодействие в BSD UNIX. Сокеты". Для обеспечения возможности работы с конкретным коммуникационным протоколом соответствующий модуль экспортирует интерфейсу сокетов функцию пользовательского запроса. При этом данные от прикладного процесса передаются от интерфейса сокетов требуемым транспортным модулям с помощью соответствующих вызовов экспортированных функций. И наоборот, данные, полученные из сети, проходят обработку в соответствующих модулях протоколов и помещаются в очередь приема сокета-адресата.

1 ... 108 109 110 111 112 113 114 115 116 ... 130
На этой странице вы можете бесплатно читать книгу Операционная система UNIX - Андрей Робачевский бесплатно.
Похожие на Операционная система UNIX - Андрей Робачевский книги

Оставить комментарий