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

1 ... 69 70 71 [ 72 ] 73 74 75 ... 98


значениях: если локальная функция возвращает значение типа int, ее RPC-партнер возвращает значение типа int*.

Функция print! создается пользователем вручную из функции print и определяется в отдельном файле print J.c следующим образом:

/* файл print l.c: определение серверной функции print */ finclude <stdio.h> finclude print.h

int* print l { char** msg )

static int result;

FILE* ofp = fopen ( /dev/console , w ); if (ofp) {

fprintf( ofp, %s\n , *msg );

fclose( ofp );

result = 1;

else result = 0; return sresult;

Определения print и print 1 различаются главным образом тем, что значения аргументов и возвращаемые значения второй функции являются указателями. Поэтому переменная result объявляется в printl как статическая, ггобы эта функция могла возвратить ее адрес.

После определения функции printl.c можно с помощью С-компилятора откомпилировать и запустить серверную программу:

% СС -о print server print l.c print svc.c -Insl % print server

Символ амперсанда ( & ) при запуске серверной программы указывать не нужно, так как в printsvc.c определено, что эта программа должна выполняться в фоновом режиме автоматически. Опция -Insl говорит о том, что для разрешения всех ссылок серверной программы на внешние библиотечные функции RFC нужно при компоновке загрузить библиотеку libnsl.so или libnsl.a. Эта опция характерна для ОС Solaris, и на других платформах для этой цели может использоваться другая опция.

Главная функция клиентской программы должна быть определена пользователем. Эта функция вызывает удаленную функцию print 1. Приведенная ниже функция print main.c получена путем модификации функции main в print.c, в результате чего построена главная клиентская программа:

/* print main.c: главная клиентская функция */

finclude <stdio.h>

finclude print.h

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

int *res, i; CLIENT *cl;

if (argc<3) { . . MCqifv ИЖ<Я { .с.У

fprintf{ stderf, usage: %s <svc host> msg. . .\п., argv[0] ); return 1; ,

if {!{cl = clnt create( argv[l], PRINTPROG, PRINTVER, tcp ))) { clnt pcreateerror{argv[l]); return 2;

} ...

for {i=argc-l; i > 1; 1-) {

if (!(res = print l{sargv[i], cl))) {

clnt perror(cl, argv[l]);

return 3;

else if {*res==0) {

fprintf{ stderr, print l failsVn li ; return 4;

else printf( print l succeeds for %s\n , argvfi] );

return 0;

Аргументами командной строки для клиентской программы являются хост-имя машины, на которой выполняется серверная программа print, и одно или несколько сообщений, которые надо передать серверу. С целью взаимодействия с этим сервером программа-клиент вызывает функцию clntjcreate. Аргументами функции clntcreate являются хост-имя сервера, номер серверной программы и номер версии. Последний аргумент, tcp, указывает на то, что клиентский и серверный процессы будут взаимодействовать посредством транспортного протокола TCP/IP.

В случае неудачного завершения функция clntcreate возвращает NULL-указатель, после чего вызывается функция clnt pcreateerror, которая выдает сообщение об ошибке. При нормальном выполнении функция clnt create возвращает указатель CLIENT*, который используется в качестве значения второго аргумента при последующем вызове функции print l. Функция print 1 для клиентской программы определяется в файле printclnt.c. Это фиктивная функция, которая, в свою очередь, вызывает функцию print 1 серверной программы.

Если клиентская функция printl возвращает NULL-указатель, это означает сбой вызова удаленной функции (по какой-то причине указанный механизм транспортировки не доступен или не работает). В этом случае вызывается функция clntjperror, которая сообщает причину отказа. Если print l возвращает не NULL-указатель, то проверяется указатель res для определения кода возврата функции printl. Возможные значения кода состояния зависят от приложения, и для разных RPC-функций они разные.

Клиентская программа генерируется путем совместной компиляции модулей ;?п>1/ /яа/ л.с и рпи/ clnt.c:

СС -о print client print clnn;5tprint main.c -lnsj



Предположим, что профамма printserver работает в фоновом режиме на машине fruit. Профамму printjclient можно запустить на любой машине, соединенной с машиной fruit локальной или глобальной сетью:

% print client fruit Hello world Good-bye print l succeeds for Hello world print l succeeds for Good-bye

В окне системной консоли на машине fruit должны появиться такие сообщения:

Hello world Good-bye

12.3.1. Функция clnt create

Функция clntjcreate имеет следующий синтаксис;

#include <фс/фс.Ь> CLIENT*

dntjcreate ( const char* hostname, const ujong prognum,

const uJong versnum, const char* nettype);

Переменная hostname - это символьная строка, заканчивающаяся NULL-СИМВОЛОМ. Она задает имя удаленной мащины, на которой работает серверный процесс.

Переменные prognum и versnum - это соответственно номер профаммы и номер версии вызываемой удаленной функции.

Переменная nettype - это символьная строка, заканчивающаяся NULL-символом. Она указывает, какой механизм необходимо использовать для связи между клиентом и сервером. Ниже перечислены возможные значения этого аргумента.

Значение nettype Смысл

netpath

visible

circuit v datagram v circuit n datagram n

i, Выбрать транспортный протокол из списка, заданного в переменной среды NETPATH. Если NETPATH не задана, выбрать транспортный протокол из условия nettype= visible (т.е. из списка, который задан в файле /etc/netcojtfig)

То же, что и netpath * Выбрать транспортный протокол из тех элементов заданного , } в файле /etc/netconfig списка, у которых установлен флаг v То же, что и visible , но выбрать транспортный протокол с

установлением соединения > (I То же, что и visible , но выбрать транспортный протокол без установления соединения

То же, что и netpath , но выбрать транспортный протокол с установлением соединения

То же, что и netpath , но выбрать транспортный протокол без установления соединения

Значение nettype

Смысл

udp

Использовать UDP

tcp

Использовать TCP

Если значение nettype равно netpath , , circuit ri или datagramji , то для определения транспортного протокола, который необходимо использовать для RPC-коммуникаций, клиентский и серверный процессы обращаются к переменной среды NETPATH. Переменная среды NETPATH определяется пользователем и содержит перечень разделенных двоеточиями названий транспортных протоколов. Ниже приведен пример команды shell, определяющей эту переменную:

% setenv NETPATH tcp:udp

При неудачном завершении функция clnt create возвращает NULL, а в случае успеха - указатель CLIENT*, который используется для связи с серверным процессом.

Функция clnt create специфична для ОС UNIX System V.4. В ONC для создания указателей на RPC-клиентов применяются следующие функции:

#include <rpc/rpc.h>

CLIENT* cinttcpjcreate (struct sockaddr ln* svraddr, const u long prognum, const u long versnum, int* sock p, const u long sendbuf size, const uJong recvbuf size);

CLIENT* cintudpjcreate (struct sockaddr in* svr addr, const uJong prognum, const uJong versnum, struct timeval retry timeout, int* sock p);

Функции clnttcp create и cintudpjcreate - это версии clntjcreate для TCP и UDP соответственно. Эти функции организуют взаимодействие клиентского и серверного процессов с использованием гнезд, и переменная NETPATH не задействуется. Значение аргумента svrjaddr - указатель на адрес гнезда хост-имени сервера, а значение аргумента sockj) - указатель на номер порта гнезда RPC-сервера. Номер порта гнезда может бьггь задан как RPC ANYSOCK, что означает порт, который фактически используется сервером.

Наконец, значение аргумента retry timeout показывает, как долго клиентский процесс должен ожидать ответа сервера до повторной передачи запроса.

12.3.2. Программа rpcgen

Синтаксис вызова профаммы rpcgen выглядит следующим образом:

rpcgen [<опции>]<входной файл>



Аргумент <входной файл> - это путевое имя файла *.х, созданного пользователем. В этом файле указываются номер RPC-программы, номер версии (или номера версий) и номер процедуры (или номера процедур). Кроме того, в этом же файле определяется пользовательский тип данных, используемый в качестве входного аргумента и/или возвращаемого значения функций RFC.

При выполнении программы rpcgen можно задавать разные опции, среди которых самое важное значение имеют следующие.

Опция rpcgen

Назначение

-К <время>

-S <механизм транспортировки>

Показывает, по истечении какого времени серверный процесс должен завершиться после обслуживания клиентского запроса. Если данная опция не задана, то используется ее значение по умолчанию, равное 120 секундам. Если установить значение опции <время> равным -1, то серверный процесс не завершится никогда

Задает механизм транспортировки, который должен использоваться для серверного процесса. Возможные значения опции <меха-низм транспортировки> идентичны значениям nettype в вызове clnt create

Рассмотрим, например, команду, которая вызывает rpcgen для компиляции файла msg.x. Эта серверная программа, созданная из соответствующего файла msg svc.c, будет существовать в течение 60 секунд после обслуживания клиентского запроса. Для связи с клиентским процессом она будет использовать один из ориентированных на соединение транспортных протоколов категории visible, заданных в файле /etc/netconfig:

% rpcgen -К 60 -s circuit v msg.x

12.3.3. Получение списка файлов каталога с помощью программы rpcgen

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

Входной файл scan.x выглядит так:

/* scan.x: получение перечня файлов каталога */ const MAXNLEN = 255;

struct complex { unsigned ival;

char ary[80];

int *ptr;

long Ival;

float dval;

typedef string name t<MAXNLEN>;

typedef struct arg rec *argPtr;

struct arg rec {

name t dir name; int Iflag;

typedef struct dirinfo *infolist;

struct dirinfo {

name t name; /* имя каталога */

u int uid; /* UID */

u long modtime; /* время последней модификации *,(.,

infolist next; /* указатель на связный список */

);

union res switch (int errno) { case 0: infolist list; default: void;

program SCANPROG {

version SCANVER {

res SCANDIR(argPtr) = 1;

) = 1; ) = 0x20000100;

Тип входного аргумента RPC-функции scandir l - адрес указателя на переменную типа struct arg rec, которая задает путевое имя каталога (поле struct argrecr.dirjtame) и целочисленный флаг (поле struct arg rec::lflag). В случае успешного выполнения функции выводится связный список записей типа struct dirinfo, в каждой из которых содержится информация о файле. Определение name t говорит о том, что имя файла - это символьная строка, содержащая максимум MAXNLEN символов и заканчивающаяся символом NULL.

Номер программы, номер версии и номер процедуры заданы как 0x20000100, 1 и 1.

Программа rpcgen компилирует scan.x при помощи следующей команды: * rpcgen scan.x



1 ... 69 70 71 [ 72 ] 73 74 75 ... 98

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