Скачиваний:
107
Добавлен:
01.05.2014
Размер:
314.88 Кб
Скачать

Принцип работы

По существу, собственно система RPC является встроенной в программу-клиент и программу-сервер, поэтому что при разработке распределенных приложений, не придется вникать в подробности протокола RPC или программировать обработку сообщений. Система предполагает существование соответствующей среды разработки, которая значительно облегчает жизнь создателям прикладного программного обеспечения. Одним из ключевых моментов в RPC является то, что разработка распределенного приложения начинается с определения интерфейса объекта формального описания функций сервера, сделанного на специальном языке. На основании этого интерфейса затем автоматически создаются заглушки клиента и сервера. Единственное, что необходимо сделать после этого, — написать фактический код процедуры.

В качестве примера рассмотрим RPC фирмы Sun Microsystems. Система состоит из трех основных частей:

  • rpcgen(l) RPC-компилятор, который на основании описания интерфейса удаленной процедуры генерирует заглушки клиента и сервера в виде программ на языке С;

  • библиотека XDR (eXternal Data Representation), которая содержит функции для преобразования различных типов данных в машинно-независимый вид, позволяющий производить обмен информацией между разнородными системами;

  • библиотека модулей, обеспечивающих работу системы в целом.

Рассмотрим пример простейшего распределенного приложения для ведения журнала событий. Клиент при запуске вызывает удаленную процедуру записи сообщения в файл журнала удаленного компьютера.

Для этого придется создать как минимум три файла: спецификацию интерфейсов удаленных процедур log.x (на языке описания интерфейса), собственно текст удаленных процедур log.c и текст головной программы клиента main ( ) — client.c (на языке С) .

Компилятор rpcgen на основании спецификации log.x создает три файла: текст заглушек клиента и сервера на языке С (log_clnt.c и log_svc.c) и файл описаний log.h, используемый обеими заглушками.

Рассмотрим исходные тексты программ.

log.x

В этом файле указываются регистрационные параметры удаленной процедуры — номера программы, версии и процедуры, а также определяется интерфейс вызова — входные аргументы и возвращаемые значения. Таким образом, определена процедура RLOG, в качестве аргумента принимающая строку (которая будет записана в журнал), а возвращаемое значение стандартно указывает на успешное или неудачное выполнение заказанной операции.

program LOG_PROG {

version LOG_VER {

int RLOG (string) = 1;

} = 1;

} = 0х31234567;

Компилятор rpcgen создает файл заголовков log.h, где, в частности, определены процедуры:

log.h

/*

*Please do not edit this file.

It was generated using rpcgen.

*/

# ifndef _LOG_H_RPCGEN

# define _LOG_H_RPCGEN

# include <rpc/rpc.h>

/*Номер программы*/

# define LOG_PROG ((unsigned long) (0х31234567))

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

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

extern int *rlog_l();

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

extern int log_prog_l_freeresult ( ) ;

# endif /* !_LOG_H_RPCGEN */

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

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

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

log.c

# include <rpc/rpc.h>

# include <sys/types, h>

# include <sys/stat.h>

# include "log.h"

int *rlog_l (char **arg)

{

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

static int result;

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

int len;

result = 1;

/*0ткроем файл журнала (создадим, если он не существует), в случае неудачи вернем код ошибки result = 1.*/

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

0_CREAT | 0_RDWR | 0_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 обменивается данными с сервером удаленной процедуры и, наконец, передает возвращаемое значение клиенту. Для клиента вызов удаленной процедуры сводится к вызову заглушки и ничем не отличается от обычного локального вызова.

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 Адрес_хоста\п",

argv [0]); exit (1);

}

server " argv [1];

/*Получим дескриптор клиента. В случае неудачи — сообщим о невозможности установления связи с сервером*/

if ( (с1 = cint_create (server,

LOG_PROG, LOG_VER, "udp")) "NULL) {

clnt_pcreateerror (server) ;

exit (2);

}

/*Выделим буфер для строки*/

mystring = (char *) mа11ос (100);

/*0прелелим время события*/

bintime = time((time_t *)NULL); cinttime = ctime(&bintime);

sprintf (mystring, "%s — Клиент запущен", cinttime);

/*Передадим сообщение для журнала — время начала работы клиента.

В случае неудачи — сообщим об ошибке*/

if ( (resuit = rlog_l(&mystring, cl)) " NULL) (

fprintf (stderr, "error2\n"); clnt_perror(cl, server);

exit (3); )

/*B случае неудачи на удаленном компьютере сообщим об ошибке*/

if (*result !=0 )

fprintf(stderr, "Ошибка записи в журнал\n"); /*0свободим дескриптор*/

clnt_destroy(cl) ;

exit (0) ;

Заглушка клиента log_clnt.c компилируется с модулем client.c для получения исполняемой программы клиента.

cc -о rlog client.c log_clnt.c -lnsl

Заглушка сервера log^sve.c и процедура log.c компилируются для получения исполняемой программы сервера.

cc -о logger log_svc.c log.c -Insl

Теперь на некотором хосте server.nowhere.ru необходимо запустить серверный процесс:

$ logger

После чего при запуске клиента rlog на другой машине сервер добавит соответствующую запись в файл журнала.

Схема работы RPC в этом случае приведена на рис. 1. Модули взаимодействуют следующим образом:

1. Когда запускается серверный процесс, он создает сокет UDP и связывает любой локальный порт с этим сокетом. Далее сервер вызывает библиотечную функцию svc_register( ) для регистрации номеров программы и ее версии. Для этого функция обращается к процессу portmap( ) и передает требуемые значения. Сервер portmap( ) обычно запускается при инициализации системы и связывается с некоторым общеизвестным портом. Теперь portmap( ) знает номер порта для нашей программы и версии. Сервер же ожидает получения запроса. Заметим, что все описанные действия производятся заглушкой сервера, созданной компилятором rpcgen( ).

2. Когда запускается программа rlog, первое, что она делает, — вызывает библиотечную функцию clnt_create( ), указывая ей адрес удаленной системы, номера программы и версии, а также транспортный протокол. Функция направляет запрос к серверу portmap( ) удаленной системы server.nowhere.ru и получает номер удаленного порта для сервера журнала.

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

server.nowhere.ru

Рис. 1

Соседние файлы в папке Лекции по сетям в формате doc