|
Программирование >> Структура ядра и системные вызовы
в результате компиляции образуются четыре файла: scan.h, scan svc.c, scan clnt.c, scan xdr.c. Последний файл содержит функции XDR-преобразо-вания для значений данных типа struct arg rec и struct dirinfo. Функция scandir l для этой серверной программы определяется в файле scandir.c: tinclude <rpc/rpc.h> tinclude <dirent.h> tinclude <string.h> tinclude <malloc.h> tinclude <sys/stat.h> tinclude scan.h extern int errno; res* scandir l(argPtr* darg) DIR *dirp; struct dirent *d; infolist nl, *nlp; struct stat statv; static res res; if {!(dirp = opendir{{*darg)->dir name))) { res.errno = errno; return &res; xdr free(xdr res, (void*)&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; if {{*darg)->lflag) { char pathnm[256]; sprintf(pathnm, %s/%s ,(*darg)->dir name,d->d name); if (!stat(pathnm,sstatv)) { nl->uid = statv.st uid; nl->modtime = statv.st mtime; *nlp = NULL; res.errno = 0; closedir(dirp); return &res; Функция scandir l вызывает API opendir для получения указателя на просматриваемый каталог, имя которого задано входным аргументом функции (*darg)->dir name. В случае неудачи opendir функция scandir l возвращает в поле res.ermo значение errno. Если вызов ореиЛг заверщается успещно, функция многократно вызывает readdir тя получения имен всех файлов в указанном каталоге. Для каждого полученного файла динамически вьщеляется запись struct dirinfo. В эту запись функция заносит имя файла и, возможно, UID владельца и время последней модификации (если значение (*darg)->lflag не равно нулю). Записи struct dirinfo объединяются в связный список, указатель на который возвращается в поле res.res u.list. Серверная профамма компилируется и запускается следующим образом: % СС scan l.c scan xdr.c scan svc.c -О scan svc -Insl % scan svc Клиентская главная профамма находится в файле scanjnain.c: finclude <stdio.h> ♦include scan.h extern int errno; int main { int arcfey* char* argv[]) ( ШЬ CLIENT *cl; char* server; struct arg rec *iarg = (struct arg rec*)malloc(sizeof(struct arg rec)); res *result; infolist nl; if (argcO) { fprintf(stderr, usage: %s host directory [<long>]\n , argv[0]); return 1; , server = argv[l]; iarg->dir name = argvi2]; iarg->lflag = 0; if (argc==4 && SScanf(argv[3], %u ,S(iarg->lflag))! =1) { fprintf(stderr, Invalid argument: %s\n , argv[3]); return 2; If <{cl = clnt create(server, SCANPROG, SCANVER, visible ))) { clnt pcreateerror(server); return 3; result = scandir l(&iarg, cl); if (!result) { clnt perror(cl, server); return 4; if (result->errno) { errno = result->errno; perror(iarg->dir name); return 5; for (nl=result->res u.list; nl; nl=nl->next) { if (iarg->lflag) printf( ...%s, uid=%d, mtime=%s , nl->name, nl->uid, ctime(snl->modtime)); else printf( ...%s\n , nl->name); return 0; Клиентская программа вызывается с хост-именем серверного процесса, именем удаленного каталога и целочисленным флагом, который показывает, указывать ли для файлов заданного каталога UID владельца и время последней модификации (значение Iflag не равно нулю) или этого делать не нужно (значение Iflag равно нулю). Клиентская функция main вызывает clnt create, чтобы получить адрес конечной точки транспортировки для подключения указанного серверного процесса. После этого все данные входных аргументов упаковываются в динамически распределяемую память (на которую указывает переменная iarg), а затем вызывается RPC-функция scandir l. По значению, возвращенному этой функцией, определяют, успешно ли выполнен данный RPC. Если вызов выполнен успешно, информация об удаленном файле направляется на стандартный вывод. В противном случае пользователь получает сообщение об ошибке. Клиентская программа компилируется и запускается следующим образом (подразумевается, что сервер работает на машине ): % СС scan main.c scan xdr.c scan clnt.c -о scan cls -InslJ % scan cls fruit /etc 1 ...magic, uid=2, mtime=Wed Aug 3 11:32:33 1997 ...protocols, uid=10, mtime=Wed Aug 3 11:32:30 1997 12.3.4. Недостатки компилятора rpcgen Тот факт, что rpcgen скрывает от пользователей низкоуровневые API RPC, имеет не только преимущества, но и недостатки. К преимуществам rpcgen можно отнести сокращение затрат на программирование и уменьшение вероятности появления ошибок. Кроме того, пользователи могут уделить больше внимания созданию RPC-функций и клиентских функций main, а не функций транспортного интерфейса RPC. В то же время компилятору /-/сеи присущи следующие недостатки: пользователи не могут непосредственно управлять теми параметрами передачи данных, которые используют серверные и клиентские программы, генерируемые компилятором; пользователи не могут управлять динамической памятью, которой пользуются XDR-функции, генерируемые компилятором; большинство компиляторов rpcgen не генерируют С++-совместимые клиентские и серверные фиктивные функции. Для того чтобы сделать эти фиктивные функции приемлемыми для компилятора С++, может понадобиться ручная доводка (отметим, что rpcgen на рабочих станциях фирмы Sun Microsystems имеет опцию -С, которая позволяет генерировать С++-совместимые файлы). Учитывая это, пользователям следует изучать низкоуровневые интерфейсы прикладного программирования RPC. Это позволит им преодолеть перечисленные выше ограничения, которые могут стать серьезным препятствием для разработки приложений. 12.4. Низкоуровневый интерфейс программирования RPC Низкоуровневые интерфейсы прикладного программирования RPC объявляются в заголовке <фс/фс.Ь>. Эти API обеспечивакуг создание клиентских и серверных процессов с заданными пользователем парамефами транспортировки данных, регистрацию RPC-функций в демоне rpcbind, вызов удаленных RPC-функций из клиентских процессов. С помощью этих API клиентские процессы могут задавать методы аутентификации для установления защищенных соединений с серверными процессами. Прежде чем представить читателю эти низкоуровневые API удаленньпс вызовов процедур, мы рассмотрим методы создания XDR-функций. Это объясняется тем, что некоторые низкоуровневые API RPC требуют, чтобы для аргументов и возвращаемых значений RPC-функций были заданы фактические данные и соответствующие XDR-функции. Кроме того, создавая собственные XDR-функции, пользователи получают возможность непосредственно управлять распределением и освобождением динамической памяти. 12.4.1. Функции XDR-преобразования При каждой операции обмена данными между клиентским и серверным процессами XDR-функция вызывается дважды. Данные, которые клиент передает в RPC-функцию, сначала преобразуются в формат XDR и лишь затем пересылаются по сети. Этот процесс преобразования называется сериализацией. Перед тем как RPC-функция-адресат получит эти данные, такая же XDR-функция вызывается уже на стороне сервера и преобразует эти данные из формата XDR в формат, принятый на хост-машине. Этот ХПР взывается десериализацией. Имеются встроенные базовые функции XDR-npeo6pa30BaHHH для большинства основных типов данных RPC. Эти базовые функции способны выполнять и сериализацию, и десериализацию. JvpoMe того, пользовательские XDR-функции (которые, в свою очередь, вызывают базовые XDR-функции) автоматически наследуют эти возможности. Перечислим встроенные базовые XDR-функции.
Типы данных ujnt, и Jong и т.д. - это беззнаковые версии типов данных int, long и г л- Данные типа />оо/преобразуются компилятором rpcgen в данные типа boolj, а тип boolj определяется в С как typedef enum { TRUE=1, FALSE=0 } bool t; Тип данных opaque соответствует последовательности произвольных байтов. Его можно использовать для объявления массивов фиксированного или переменного размера, например: opaque opaque х[561; vx<56>; Компилятор rpcgen преобразует эти определения следующим образом: char X [ 5 6]; struct { u int char XV len; /* фактическая длина массива xc val */ *хс val; /* динамический массив */ Если пользователи определяют собственные типы данных, они могут генерировать XDR-функции для этих типов с помощью rpcgen или же писать собственные функции XDR-преобразования. Например, если пользователь определяет тип данных struct complex следующим образом: struct complex ( unsigned char uval; ary[80]; long double *ptr Ival dval TO XDR-функция для struct complex будет вьплядеть так: . boot t xdr complex(XDR* xdrs, struct complex* objp) { if {!xdr u int(xdrs, &objp->uval)) return FALSE; if (lxdr vector(xdrs, objp->,80, sizeof(char), {xdrproc t)xdr char) return FALSE; if {!xdr pointer(xdrs, &objp->ptr, sizeof(int), (xdrproc t)xdr int)) return FALSE; if (!xdr long(xdrs, &objp->lval)) return FALSE; if (!xdr double(xdrs, &objp->dval)) return FALSE; return TRUE; Bee XDR-функции возвращают значения типа boolj. TRUE, если функция выполнена успешно, FALSE в противном случае. XDR-функция для типа complex состоит из вызова базовой XDR-функции, которая преобразует все поля записи complex. Обратите внимание на тот факт, что массив фиксированного размера сотр1ех::агу преобразуется встроенной XDR-функцией xdr vector, которая имеет следующие аргументы: указатель на буфер, в котором содержатся преобразованные данные; адрес массива фиксированного размера; число элементов массива; размер каждого элемента и XDR-функция, преобразующая каждый элемент массива. Член complexr.ptr преобразуется еще одной встроенной XDR-функцией, xdrjointer, которая имеет следующие аргументы: указатель на буфер, содержащий преобразованные данные; адрес указателя; размер данных, на которые он указывает, и XDR-функция для этих данных. 12.4.2. Низкоуровневые API удаленных вызовов процедур Существуют два набора интерфейсов прикладного программирования RPC для создания на базе RPC клиентских и серверных программ (по одному для каждого вида). Эти API и последовательность их вызова в клиентском и серверном процессах показаны на рис. 12.1. Надписью clnt <create RPCJandle> обозначен набор API RPC. Кюкдый API RFC из этого набора создает интерфейс к RPC-клиенту, который можно использовать для связи с RPC-сервером для указанных номера RPC-npo-граммы и номера версии. Эти API перечислены ниже; они различаются по степени детализации при указании сетевого транспортного протокола, используемого для связи с RPC-сервером.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |