Программирование >>  Структура ядра и системные вызовы 

1 ... 80 81 82 [ 83 ] 84 85 86 ... 98


которая генерирует временный номер программы. После этого активизируется API svcreg, который связывает номер программы и номер версии с соответствующей функцией-диспетчером.

Функция API svc reg имеет следующий прототип:

#include <rpc/rpc.h>

int svc reg (const SVCXPR* xprt, const uJong prognum,

const uJong versnum, const void {*dispath){...), const struct netconfig* netconf);

Аргумент xprt - это обработчик сервера. Аргументы prognum и versnum - это номер программы и номер версии, связанные с функцией-диспетчером, заданной аргументом dispatch. Аргумент netconf задает метод транспортировки, который может использоваться для регистрации RPC-функции и функции-диспетчера демоном rpcbind. Если аргумент netconf имеет значение NULL, такая регистрация не требуется.

В функции-конструкторе RPC svc функция svcreg вызывается с нулевым значением аргумента netconf (если вызывается RPC svc::genj)rogNum). Это объясняется тем, что функция RPC svc::gen progNum автоматически регистрирует RPC-функцию демоном rpcbind.

В случае неудачи API svc reg возвращает FALSE; в противном случае возвращается TRUE и RPC-сервер настраивается нормально.

Программу aclk cls.C можно переписать с использованием перегруженной функции-конструктора RPC svc::RPC svc, которая создает временный номер программы. Новая программа aclk cls2.Cвытлятг следующим образом:

tinclude <netconfig.h> tinclude aclock.h finclude RPC.h

RPC svc *svcp = 0;

tdefine CLNTPROGNUM 0x20000105

/* функция обратного RPC-вызова клиента */

int callback( SVCXPRT* xtrp )

u long timv;

/* получить значение времени, оставшегося до сигнала будильника */ if (svcp->getargs(xtrp, (xdrproc t)xdr u long, (caddr t)Stimv)!=RPC SUCCESS)

cerr client: get alarm time fails\n ; return -1;

cerr client: alarm time ,left is: timv endl;

/* возвращает серверу полученные значения */

if (svcp->reply(xtrp, (xdrproc t) xdr void., 0) !=RPC SUCCESS)

cerr client: send reply failedXn ; return -2;

/* выполнять другую работу, затем заверщить клиентский процесс */ exit(O) ;

/* зарегистрировать обратный вызов на RPC-сервере */

int register callback( char* local host, char* svc host, u long alann time)

struct arg rec argRec; ff-t

/* сообщить удаленному серверу хост-имя процесса, номер

программы, номер версии, номер функции и заданный интервал времени до сигнала будильника */

argRec.hostname = local host;

argRec.prognum = svcp->progno();

argRec.versnum = CLNTVERNUM;

argRec.procnum = CLNTPROCNUM;

argRec.atime = alarm time;

/* настроить клиентский объект на соединение с RPC-сервером */ RPC cls clnt( svc host, ACLKPROG, ACLKVER, netpath ); if (!clnt.good()) return 1;

/* вызвать RPC-функцию сервера (set alarm) */

if (clnt.call( ACLKPROC, (xdrproc t)xdr arg rec, (caddr t)sargRec, (xdrproc t)xdr void, (caddr t)0 ) !=RPC SUCCESS)

return 2;

cerr client: getpidO : RPC called doneXn ; return 0;

/* главная клиентская функция */ int main (int argc, char* argv[])

if (argc!=4) {

cerr usage: argv{0] <local-host> <svc-host>

<transport>Xn ;

return 1;

/* создать серверный объект для приема обратного вызова от

удаленного сервера */ if (!(svcp= new RPC svc ( RPC ANYFD., argyO], 0, CLNTVERNUM ))) return 2;



/* определить функцию обратного вызова */. , svcp->aclcljproc ( CLNTPROCNUM, callback ) ;

/* зарегистрировать обратный вызов на удаленном сервере */ if (register callback( argv[l], argv[2], 10)) return 3;

/* выполнить другую работу ... */

svcp->runО; /* ожидать истечения заданного интервала времени

до сигнала будильника */

return 0;

Новая программа отличается от описанной в разделе 12.9 одной строкой, в которой с помощью оператора new в главной функции создается указатель RPC svc.

Эту программу можно компилировать и запускать так, как показано в разделе 12.9. Результаты выполнения старой и новой программ одинаковы.

12.11. RPC-услуги на базе inetd

RPC-серверы - это, как правило, процессы-демоны, которые работают непрерывно, ожидая поступления RPC-вызовов от клиентов. Недостаток такой схемы в том, что системные ресурсы, выделенные этим процессам (например, элементы таблицы процессов), не могут использоваться другими процессами даже тогда, когда эти демоны простаивают. Повысить эффективность использования системных ресурсов можно с помощью программ мониторинга портов, например inetd, которые позволяют управлять сетевыми адресами для RPC-услуг тогда, когда RPC-серверы не выполняются. Когда поступает RPC-запрос, монитор порта порождает RPC-сервер, который отвечает на этот запрос и самозавершается после предоставления услуги. Таким образом, системные ресурсы выделяются RPC-серверу только на то время, которое необходимо для ответа на запрос клиента.

В большинстве коммерческих UNIX-систем для мониторинга порта используется программа inetd. Она запускается при начальной загрузке системы и из файла /etc/inetd.conf получает сетевые адреса, которыми может управлять. Каждый элемент этого файла имеет следующий синтаксис;

<сервис> <средство транспортировки> <протокол> <wait> <uid> <программа> <арг>

Такая запись означает, что если поступает запрос на указанный сервис (<сервис>), inetd тлжен выполнить программу <программа>, указав значение <арг> в качестве ее аргумента. Действующий UID выполняемой программы задается полем <uid>, а для связи с клиентским процессом используются указанные средство транспортировки и протокол. В полях <средство транспортировки> и <протокол> используются следующие значения:

Средство транспортировки

Протокол

stream

dgram

Для сервисов, использующих гнезда, в поле <wait> указываются следующие значения: nowait - для транспортировки с установлением соединения (tcp), wait - для транспортировки без установления соединения (udp). Для хервисов на базе ТЫ в поле <wait> обьгано устанавливается wait.

Адрес порта сервиса указывается в файле /etc/services следующим образом: <сервис> <порт>/<протокол>

Предположим, что в файле /etc/inetd.conf тлеется следующая запись:

login stream tcp nowait root /etc/in.rlogind in.rlogind

Когда удаленный пользователь попытается зарегистрироваться на локальной хост-машине, профамма inetd должна выполнить профамму /etc/in.logind от имени пользователя root. Процесс rlogin будет использовать фанспортный протокол TCP/IP и адрес порта 513, как указано в файле /etc/services:

login 513/tcp

Чтобы профамма inetd проверяла наличие конкретного RPC-запроса, в файл /etc/inetd.conf следует ввести запись для этого RPC-сервера:

<номер прог>/<номер верс> <средство транспортировки> <протокол> <wait> \ <uid> <программа> <арг>

Здесь <номер прог> и <номер верс> - это номера профаммы и версии RPC-сервера. Остальные поля такие же, как для вышеупомянутого RPC на базе ONC. В ОС UNIX System V.4 поле <средство транспортировки> может содержать значение tli, если обработчик RPC-сервера создается на основе TLI, а поле <протокол> может содержать значение rpc/tcp, rpc/udp или rpc/*. Значение rpc/* указывает на то, что сервер может пользоваться любым механизмом фанспортировки, который поддерживается интерфейсом ТЫ.

Например, в профамме вывода содержимого каталога из раздела 12.7.4 используется номер профаммы 0x200100 и номер версии 1. Чтобы inetd поддерживал этот сервис, необходимо ввести в файл /etc/inetd.conf следующую запись (подразумевается, что выполняемый файл RPC-сервера имеет имя /proj/scanjsvcJ):

Для ONC:

# 536871168 is same as 0x20000100

536871168/1 stream tcp wait root /proj/scaft svc3 scan svc3

Для UNIX System V.4: 536871168/1 tli rpc/* wait root /proj/scan svc3 scan svc3



Помимо конфигурирования inetd, RPC-сервер должен создать свой обработчик RPC svc (класс RPC svc описан в разделе 12.5) с помощью конструктора:

RPC svc::RPC svc(int fd, char* transport, unsigned long progno, unsigned long versnum);

Для того чтобы аргумент fd конструктора RPC svc соответствовал входящему RPC-запросу, демон присваивает ему значение 0. В приведенном выше примере сервер должен создать свой обработчик RPC svc следующим образом:

RPC svc *svcp = new RPC svc(0, tcp , 0x20000100, 1);

Ниже перечислены API, с помощью которых конструктор RPC svc::RPC svc создает обработчик RPCjsvc. В ONC:

для создания обработчика сервера вызывается svclcpjcreate (для механизма транспортировки, использующего потоки) или svcudpjcreate (для механизма транспортировки на основе дейтаграмм);

для регистрации функции-диспетчера, которая будет вызываться при поступлении RPC-вызова, вызывается svc reg.

В UNIX System V.4:

чтобы создать объект типа struct netconfigрдя необходимого транспортного протокола (tcp или udp), вызывается getnetconfigent;

для создания обработчика сервера вызывается svctlijcreate;

для регистрации функции-диспетчера, которая будет вызываться при поступлении RPC-вызова, вызывается svc reg.

Тот, кого интересует последовательность вызова этих API, может обратиться к коду конструктора RPC svc, приведенному в разделе 12.5.

Мы перечислили все изменения, которые необходимо внести, чтобы получить возможность управлять запросами RPC-сервиса с помощью inetd. Остальная часть кода сервера не изменилась. Более того, в XDR-функциях и клиентских программах, выполняющих RPC-вызовы, вообще ничего изменять не нужно.

В качестве последнего примера возьмем программу вывода списка файлов каталога, приведенную в разделе 12.7.4, и перепишем ее так, чтобы сервер использовал inetd для управления RPC-запросами. Тексты программы-клиента (scan cls2.Q и XDR-функции (scanxdr.c) содержатся в разделе 12.7.4, поэтому здесь не повторяются. Ниже приведена модифицированная серверная программа scansvcJ. С.

/* серверная программа: использование API RPC низкого уровня */

/* вызов: scan svc3 <ttl> */

linclude <stdio.h> finclude <stdlib.h>

finclude <dirent.h> finclude <string.h> finclude <malloc.h> finclude <sys/stat.h> finclude <sys/resource.h> finclude <signal.h> finclude scan2.h finclude RPC.h

char* transp = tcp ;

extern int errno;

static RPC svc *svcp = 0; static int work in progress = 0;

static int ttl = 60; /* время жизни 60 СекуИд */

/* RPC-функция */ int scandir( SVCXPRT* xtrp ) (

DIR *dirp; struct dirent *d/ infolist nl, *nlp; struct stat statv; res res;

argPtr darg = 0;

work in progress = 1; /* процесс не уничтожен сигналом

будильника */

/* получить аргумент функции от клиента */ if (svcp->getargs( xtrp, (xdrproc t)xdr argPtr, (caddr t)Sdarg)!=RPC SUCCESS)

return -1;

cerr server: get dir: darg->dir name , lflag=

darg->lflag endl/

/* начать просмотр затребованного каталога */ if (.(dirp = opendir (darg->dir name))) ( res.errno = errno;

(void)svcp->reply(xtrp, (xdrproc t)xdr res, (caddr t)fires); return -2;

/* освободить память, вьщеленную в предыдущем RPC-вызове */ xdr fгее((xdrproc t)xdr res, (char*)fires);

/* занести информацию о файлах в res как возвращаемые значения */ nip = fires.res u.list; while (d=readdir(dirp)) (

nl = *nlp = (infolist)malloc(sizeof(struct dirinfo));

nl->name = strdup(d->d name);

nip = finl->next;

if (darg->lflag) (



1 ... 80 81 82 [ 83 ] 84 85 86 ... 98

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика