|
Программирование >> Структура ядра и системные вызовы
которая генерирует временный номер программы. После этого активизируется 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>, а для связи с клиентским процессом используются указанные средство транспортировки и протокол. В полях <средство транспортировки> и <протокол> используются следующие значения:
Для сервисов, использующих гнезда, в поле <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) (
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |