|
Программирование >> Структура ядра и системные вызовы
RPC-вызов завершен. Проверить код возврата функции */ (result.errno) { errno = result.errno; perror(iarg->dir name); return 5; /* RPC-функция завершается успешно. Вывести список файлов удаленного каталога */ for (nl=result.res u.list; nl; nl=nl->next) { if (iarg->lflag) cout nl->name , uid= nl->uid , mtime= ctime(&nl->modtime) endl; else cout nl->name Xn ; return 0; Программа-клиент вызывается с хост-именем сервера, именем удаленного каталога и, по желанию, с целочисленным флагом. Имя удаленного каталога - это имя каталога, содержимое которого должна возвратить данная RPC-функция. Необязательный целочисленный флаг задает формат, в котором должен быть представлен список файлов: в развернутом формате {Iflag = 1) или только с именами файлов {Iflag = 0). Программа-клиент, вызванная с правильными аргументами, создает объект RPC clsjiflH соединения с сервером при помощи функции-конструктора RPC cls::RPC cls. RPC-сервер идентифицируется константами SCANPROG, SCANVER и SCANFUNC (номер программы, номер версии и номер процедуры). После создания клиентского объекта RPC cls клиентский процесс вызывает функцию RPC cls::set, которая генерирует аутентификационную информацию клиента методом AUTH DES. Эта функция может создавать мандаты, используя AUTH NONE, AUTH SYS или AUTH DES, и скрывать все низкоуровневые API RPC-аутентификации от пользователей. Затем клиент вызывает RPC-сервер с номером процедуры О, чтобы проверить, работает ли сервер. Если функция RPC cls::call завершается неудачно, клиентский процесс выводит соответствующее сообщение об ошибке и завершает свою работу; в противном случае его выполнение продолжается. Клиент выделяет динамическую память для переменной iarg, в которой хранится входной аргумент RPC-функции: имя удаленного каталога и целочисленный флаг. Клиент вызывает RPC-функцию через функцию RPCclsrxall и указывает, что возвращаемое ею значение должно быть помещено в переменную result. Кроме того, XDR-функциями для входного аргумента и возвращаемого значения являются пользовательские функции xdrargPtr и xdrres соответственно. Если RPC-функция возвращает код успешного завершения, клиентская программа выводит на экран возвращенное значение функции (перечень содержимого удаленного каталога). Отметим, что если флаг формата отображения содержимого каталога равен 1, то информация о каждом файле включает его имя, UID и время последней модификации. Если же флаг формата равен О, то показывается только имя файла. Программа-сервер, которая выводит содержимое удаленного каталога, находится в файле scan svc2. С: ♦include ♦include ♦include ♦include ♦include ♦include ♦include ♦include <stdio.h> <stdlib.h> <dirent.h> <string.h> <malloc.h> <sys/stat.h> scan2.h RPC.h extern int errno; static RPC svc *svcp = 0; /* RPC-функция */ int scandir( SVCXPRT* xtrp ) DIR *dirp; struct dirent *d; infolist nl, *nlp; struct stat statv; res res; argptr darg = 0; /* получить от клиента аргумент функции */ if (svcp->getargs( xtrp, (xdrproc t)xdr argPtr, (caddr t)&darg)!=RPC SUCCESS) return -1; cerr server: get dir: f 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 free((xdrproc t)xdr res, (char*)&res); /* записать информацию о файлах в res как возвращаемые значения */ nip = &res.res u.list; while (d=readdir(dirp)) { nl = *nlp = (infolist)malloc(sizeof(struct dirinfo))/ nl->name = strdup(d->d name); nip == &nl->next;, j-f}. -;,u if (darg->lflag) { char pathnm[256]; sprintf (pathnm, %s/%s ,darg->dir nartie,d->d name]; if (Istat(pathnm,sstatv)) ( nl->uid = statv.st uid; nl->modtime = statv.st mtime; *nlp =0; res.errno = 0; closedir(dirp]; /* передать список содержимого каталога клиенту */ if (svcp->reply(xtrp, (xdrproc t] xdr res, (caddr t) Sres] !=RPC SUCCESS] return -2; return RPC SUCCESS; /* главная функция RPC-сервера */ int main (int argc, char* argv[]); ( svcp = new RPC svc( SCANPROG, SCANVER, netpath ]; if (svcp->run func{ SCANDIR, scandir )] return 1; return 0; /* здесь не должно быть выхода из программы */ } , Приведенная программа создает RPC-сервер, который выводит содержимое каталога. Аргументы командной строки для вызова программы не требуются. Данный процесс создает с помощью функции-конструктора RPC svc:: RPCsvc объект RPCjsvc. После этого для регистрации RPC-функции scandir в объекте RPC svc сервер вызывает функцию RPC svc::run June и ожидает поступления клиентских RPC-запросов. Получив запрос, сервер вызывает функцию RPC svc::dispafch, которая прежде всего проверяет, равен ли номер затребованной RPC-процедуры нулю. Если клиент хочет только выяснить, готов ли сервер к работе, эта функция возвращает значение NULL, в чем и состоит ответ сервера на такой запрос. Если же это не просто проверка готовности сервера к работе, функция-диспетчер проверяет запрос клиента по заданному методу аутентификации. Получив отрицательный результат, функция-диспетчер выводит сообщение о системной RPC-ощибке и завершает работу. Текущая функция RPCjsvc:: dispatch принимает только тех клиентов, у которых UID либо равен нулю (привилегированный пользователь), либо совпадает с UID серверного процесса. Установив достоверность аутентификационной информации клиента, функция-диспетчер вызывает затребованную RPC-функцию. В этом примере единственная RPC-функция - это printmsg, которая выполняет следующие операции: получает от клиентского процесса аргументы; освобождает динамическую память, выделенную переменной res в предыдущем вызове; просматривает указанный каталог и помещает информацию обо всех его файлах в переменную res; т передает переменную res как возвращаемое значение в вызывающую программу-клиент. Последние компоненты кода в этом примере - это XDR-функции для пользовательских типов данных (например, struct arg rec, argPtr, infolist w т.д.). Эти XDR-функции определяются в файле scan2 xdr.c: * Please do not edit this file. * It was generated using rpcgen. */ tinclude scan2.h /* XDR-функция для данных типа name t */ bool t xdr name t(register XDR *xdrs, name t *objp) register long *buf; if (!xdr string(xdrs, objp, MAXNLEN]) return (FALSE); return (TRUE]; /* XDR-функция для данных типа argPtr */ bool t xdr argPtr(register XDR *xdrs, argPtr *objp) register long *buf; if {!xdr pointer(xdrs, (char **)objp, sizeof (struct arg rec], {xdrproc t] xdr arg rec]) return (FALSE]; return (TRUE); /* XDR-функция для данных типа arg rec */ bool t xdr arg rec(register XDR *xdrs, arg rec *objpM* { ~ ~ - rj register long *buf; if (!xdr name t(xdrs, &objp->dir name]) return (FALSE); if (!xdr int(xdrs, &objp->lflag)) return (FALSE); return (TRUE); /* XDR-функция для данных типа infolist */ bool t xdr infolist(register XDR *xdrs, infolist *objp) register long *buf; if (!xdr pointer(xdrs, (char **)objp, sizeof (struct dirinfo), (xdrproc t) xdr dirinfo)) return (FALSE); return (TRUE); /* XDR-функция для данных типа dirinfo */ bool t xdr dirinfо(register XDR *xdrs, dirinfo *objp) register long *buf; if (!xdr name t(xdrs, &objp->name)) return (FALSE); if (!xdr u int(xdrs, &objp->uid)) return (FALSE); if (!xdr long(xdrs, &objp->modtime)) return (FALSE); if (!xdr infolist(xdrs, &objp->next)) return (FALSE); return (TRUE); /* XDR-функция для данных типа res */ bool t xdr res(register XDR *xdrs, res *objp) register long *buf; If (!xdr int(xdrs, &objp->errno)) return (FALSE); switch (objp->errno) { case 0: if (!xdr infolist(xdrs, sobjp->res u.list)) return (FALSE); breaJc; return (TRUE); Эти XDR-функции особых пояснений не требуют. Их можно генерировать вручную или с помощью rpcgen. В последнем случае пользователи должны объявить свои типы данных в файле rpcgen.x, а там, где это необходимо, использовать типы данных, характерные для rpcgen, например string. Приведенные выше клиентская и серверная программы создаются следующими командами shell: % СС -с scan2 xdr.c RPC.С % СС -DSYSV4 -о scan svc2 scan svc2.C scan2 xdr.o \ RPC.о -Isocket -Insl % CC -DSYSV4 -о scan cls2 scan cls2.C scan2 xdr.o \ RPC.о -Isocket -Insl Ниже приведены примерные результаты запуска этих программ. Серверная программа выполняется на машине fruit, а клиентскую можно запускать на любой машине, соединенной с fruit: % scan svc2 & % scan cls2 fruit . ..scan cls2.C ..scan svc2,С ..RPC.С ..RPC.h . .scan2 xdr.c ..scan2 .h ..scan svc2 ..sea n cls2 Prog 536871168 (version 1) is alive 12.8. Широковещательный режим RPC Некоторые RPC-запросы могут потребовать ответа от всех серверов в сети, предоставляющих затребованные услуги. Допустим, например, что клиентскому процессу надо установить системное время на всех машинах в локальной сети. Предположим, что на каждой машине работает RPC-сервер, действующий UID которого соответствует UID привилегированного пользователя. Клиентский процесс одним RPC-вызовом передает новое системное время в широковещательном режиме всем этим серверам, и каждый сервер соответствующим образом корректирует системное время. Чтобы использовать широковещательный режим RPC, процесс может задействовать функцию-член RPC cls::broadcast. Это статическая функция, перед выполнением которой не требуется создавать объект RPCcls. Эта функция, в свою очередь, вызывает API rpcjbroadcast, с помощью которого и реализуется широковещательная передача. Прототип этого API выглядит следующим образом:
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |