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

1 ... 77 78 79 [ 80 ] 81 82 83 ... 98


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 выглядит следующим образом:



1 ... 77 78 79 [ 80 ] 81 82 83 ... 98

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