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

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


Аргументы prelum, versnum и funcnum - это номера вызываемой RPC-функции.

Аргумент argfunc представляет собой адрес XDR-функции, используемой для сериализации и десериализации аргумента RPC-функции, заданного как argp. Аргумент resfunc - это адрес XDR-функции, используемой для сериализации и десериализации возвращаемого значения RPC-функции, которое помещается в аргумент resp.

Аргумент nettype задает способ передачи щироковещательного RPC-вы-зова. Это должен быть транспортный протокол без установления соединения, например UDP. По умолчанию аргумент nettype в функции RPCclsr.broadcast имеет значение datagram v . Это значит, что может использоваться любой протокол на основе дейтаграмм, который в файле /etc/netconfig указан как visible . Для функции rpc broadcast характерны еще два ограничения: во-первых, щироковещательный запрос по размеру не может превышать установленное для его хост-машины значение параметра МТи (для локальных сетей на базе Ethernet MTU равен 1500 байтам); во-вторых, на широковещательные RPC-запросы могут отвечать только серверы, зарегистрированные в демоне rpcbind (т.е. серверы должны быть созданы с помощью API svc create или svc tp create).

Аргумент callme - это определяемая пользователем функция, которая вызывается для каждого ответа RPC-сервера. Она имеет следующий прототип:

int caffme (caddr t resp, struct netbuf* server addr, struct netconf* nconf);

где аргумент resp принимает то же значение resp, которое указано в вызове rpcjbroadcast. Это адрес определенной в клиентском процессе переменной, которая содержит значение, возвращаемое сервером. Аргумент server addr содержит адрес отвечающего сервера, а аргумент nconf - информацию о методе транспортировки, используемом сервером.

Активизированная функция грс broadcast блокирует вызывающий процесс, заставляя его ожидать ответов от серверов. Для обслуживания каждого такого ответа эта функция вызывает функцию callme. Если функция callme возвращает значение О, то грс broadcast ожидает следующего ответа. Если функция сайте возвращает ненулевое значение, то функция rpcjroadcast завершается и передает управление вызывающему процессу.

Функция rpcjroadcast возвращает значение RPC TIMEOUT, если она ожидала и пробовала передать широковещательный запрос несколько раз,

НО не получила никакого ответа. Если функция сайте возвратила TRUE, то функция rpcjroadcast возвращает значение RPC SUCCESS; в противном случае она возвращает ненулевое значение, свидетельствующее об ошибке.

Идентификацию вызывающего процесса для всех серверных процессов, которые принимают широковещательный запрос, функция rpcjroadcast выполняет по методу AUTH SYS.

В ONC функцию rpcjroadcast заменяет API clnt broadcast. Эти функции имеют почти одинаковые сигнатуры и возвращаемые значения, но в clnt broadcast не используется аргумент nettype.

#include <rpc/rpc.h>

enum clnt stat cintjbroadcast (unsigned prognum, unsigned versnum,

unsigned funcnum, xdrproc t argfunc, caddr t argp, xdrproc t resfunc, caddr t resp, resultproc t callme);

Ниже приведен прототип функции callback для API clntjroadcast. int callme (caddr t resp, struct sockaddr in* server addr);

где аргумент resp принимает то же значение resp, которое указано в вызове clntjroadcast. Аргумент serveraddr содерушг адрес отвечающего сервера. Его тип данных - указатель на структуру, в которой хранится адрес гнезда.

12.8.1. Пример широковещательной передачи RPC-запросов

Сейчас мы изменим представленную в разделе 12.5 программу msg cls2. С, включив в нее средства широковещательного режима RPC (изменения касаются только программы-клиента). Новая программа назьгеается msg cls3. С.

I* программа-клиент: использование широковещательного режима для

вывода сообщения на системную консоль сервера */ ♦include msg2.h ♦include RPC.h

static int num responses = 0;

/* вызов широковещательного режима клиента */

bool t callme (caddr t res p, struct netbuf* addr, struct netconfig *nconf)

numresponses++; число ответивших серверов

if (res p==0 II *((int*)res p)!=0) {

cerr clnt: call printmsg failsXn ;

return TRUE; прекратитьшироковещательную передачу

}

cout clnt: call printmsg succeedsXn ;

enum clnt stat rpcjbroadcast (unsigned prognum, unsigned versnum,

unsigned funcnum, xdrproc t argfunc, caddr t argp, xdrproc t resfunc, caddr t resp, resultproc t callme, char* nettype);



return FALSE;

ожидание ответов

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

I \

int res;

if (argc<2) [ -.ША-г

cerr usage: у!1р<- argv(0] msg\n s return 1; ...

/* клиент посьшает широковещательный запрос и ждет ответа */ int rc = rpc cls::broadcast( msgprog, msgver, printmsg,

(resultproc t)callme,(xdrproc t)xdr string, (caddr t)&argv[l],(xdrproc t)xdr int, (caddr t)sres);

switch (rc) {

case rpc soccess: breaJcj

case rpc timed0ut:

if (num responses) brea)c; default:

cerr rpc broadcast failed\n ;, return 2;

cout Rpc braodcast done. No. responses: num responses endl; return 0;

Новая клиентская программа printmsg передает один аргумент командной строки как сообщение в широковещательном режиме. Для этого используется функция RPC ds::broadcast. При ее активизации клиентский процесс задает callme как функцию, которую функция rpc broadcast должна вызывать для каждого ответа сервера. Аргумент и XDR-функция программы printmsg, а также переменная, содержащая возвращаемое значение и XDR-функцию программы printmsg, устанавливаются в вызове функции RPC cls::broadcast так же, как в вызове функции RPC cls::call.

Функция callme вызывается для каждого ответа на широковещательный запрос. Эта функция просто проверяет возвращаемое значение. Если сервер возвращает код неудачного завершения, то функция возвращает TRUE и широковещательная передача прекращается; в противном случае возвращается FALSE и прием ответов продолжается. Функция callme увеличивает на единицу значение глобальной переменной num responses, в которой хранится число серверов, фактически ответивших на запрос.

После выполнения функции RPC cls::broadcast клиентская программа проверяет код возврата этой функции. Если возвращено значение RPC SUC-CESS, значит, широковещательная передача была остановлена функцией callme и все нормально. Если же возвращен код RPC TIMEOUT, то проверяется


Снстеиное програиинрованне на С++ для UNIX

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

Ниже представлены результаты работы серверной программы msg svc2 (см. разд. 12.5) и новой клиентской программы msg cls3, функционирующей в режиме широковещательных RCP-запросов:

% СС dsysv4 -О msg cls3 msg cls3.C RPC.С -Isocjcet -Insl % msg cls3 Testing RPC broadcast feature clnt: call printmsg succeeeds clnt: call printmsg succeeeds

Ha системных консолях всех машин (на которых работает демон msg svc2) выводится сообщение Testing RPC broadcast feature.

12.9. Обратный вызов RPC

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

Чтобы RPC-сервер мог выполнить обратный вызов, клиент должен указать для функции обратного вызова номер RPC-программы, номер версии и номер процедуры. В некотором смысле этот клиент исполняет роль и клиента, и сервера.

Давайте посмотрим, как это можно сделать. В приведенном ниже примере RPC-сервер предоставляет процессам в локальной сети услуги будильника. Клиентский процесс, которому нужна эта услуга, посылает серверу RCP-запрос и указывает следующую информацию:

хост-имя машины клиентского процесса;

номер программы, версии и процедуры RPC-функции обратного вызова клиента;

интервал времени в секундах до сигнала будильника (alarm clock).

Получив запрос от клиента, RPC-сервер порождает дочерний процесс, чтобы установить сигнал будильника, который будет передан порожденному процессу по истечении заданного клиентом интервала времени. Чтобы

лава 12. Удаленные вызовы процедур



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

Заголовочный файл aclock.h совместно используется клиентской и серверной программами:

fifndef ACLOCK H fdefine ACLOCK H

finclude <rpc/rpc.h>

fdefine 4AXNLEN 255

typedef char *name ;t;

/* информаиия для обратного вызова клиента RPC-сервером */ struct arg rec {

name t hostname;

u long prognum;

u long versnum;

u long procnum;

u long atime;

хост-имя машины клиента

номер программы RPC-функиии клиента

номер версии RPC-функиии клиента

номер проиедуры RPC-функиии клиента

, временной интервал для будильника

fdefine CLNTVERNUM 1 fdefine CLNTPROCNUM 1

fdefine ACLKPROG ((unsigned long)(0x20000100)) fdefine ACLKVER ((unsigned long) (1) ) fdefine ACLKPROC ((unsigned long)(1))

/* XDR-функции для преобразования данных обратного вызова клиента */ extern bool t xdr name t(XDR *, name t*); extern bool t xdr arg rec(XDR *, arg rec*);

fendif /* !ACLOCK H */

Программа RPC-сервера aclk svc.C выглядит следующим образом:

finclude <signal.h> finclude aclock.h finclude RPC.h

RPC svc *svcp;

static struct arg rec argRec;

обработчик RPC-сервера содержит информацию для обратного вызова клиента

/♦выполнить обратный вызов RPC-функиии клиента*/ void call client( int signum )

\ u long X = alarm(0); остаток интервала будильника

RPC cls cls( argRec.hostname, argRec.prognum, argRec.versnum, netpath ); if (Icls.goodO ) (

cerr call client: create RPC cls object failedXn ;

exit(l);

if (cls.dalK argRec.procnum, (xdrproc t)xdr u long, (caddr t)&x, (xdrproc t)xdr void, 0 )!=RPC SUCCESS) cerr call client: call client failedXn ;

exit(O); /* уничтожить порожденный процесс */

/* RPC-функция сервера. Вызывается клиентом для настройки сервиса

будильника */ int set alarm( SVCXPRT* xtrp ) (

/* получить информацию о клиенте: хост-имя, номер программы,

номер версии и номер процедуры функции обратного вызова RPC */ if (svcp->getargs( xtrp, (xdrproc t)xdr arg rec, (caddr t)sargRec) !=RPC SUCCESS)

return -1;

/* возвратить клиенту полученные значения */ if (svcp->reply( xtrp, (xdrproc t)xdr void, (caddr t)0)!=RPC SUCCESS) (

cerr printmsg: sendreply failedXn ; return -1;

/* создать порожденньМ процесс для работы с данным клиентом */ switch (forkО) ( .

case -1: . !] perror( cant fork ); ; N break;

case 0: /* порожденный процесс */

alarm(argRec.atime); signal(SIGALRM, call client);

ожидать истечения интервала времени до сигнала будильника

pause О ;

/* родительский процесс */ return RPC SUCCESS;

int main(int argc, char* argv[]) (

./* создать обработчик сервера для ожидания RpC-вызовов функции set alarm */,

RPC svc *svcp = new RPC Svc( ACLKPROG, ACLKVER, argc==2 ?

argv[l] : netpath );



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

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