|
Программирование >> Структура ядра и системные вызовы
RPC отличаются и рядом других преимуществ: этот механизм скрывает от программистов основные детали передачи данных по сети, делая более легкими разработку и сопровождение программ, основанных на RFC; данные, которыми обмениваются клиентский и серверный процессы, представлены в формате, не зависящем от архитектуры компьютера, (таком как XDR), что позволяет взаимодействовать мащинам с разными архитектурами (например, компьютерам с процессорами Intel х86 и рабочим станциям Sun SPARC); RPC поддерживают все сетевые транспортные протоколы (как с установлением соединений, так и без него); больщинство развитых операционных систем (в частности, UNIX, VMS и Windows NT) поддерживают RPC и совместимы друг с другом, что позволяет разрабатывать сетевые приложения, которые могут выполняться на разных платформах под управлением разных операционных систем. 12.1. История создания RPC в 80-е годы существовали разные методы реализации RPC, в частности Open Network Computing (ONC) фирмы Sun Microsystems и Network Computing Architecture (NCA) фирмы Apollo Computers. Сегодня в больщинстве коммерческих разновидностей ОС UNIX, в том числе в HP-UX (Hewlett-Packard), AIX (IBM), Sun OS 4.1.x (Sun Microsystems), SCO UNIX (Santa Cruz Operations), RPC реализованы no методу ONC. Однако в операционной системе Solaris 2.x (Sun Microsystems) и в ОС UNIX System V.4 для реализации RPC применяется модифицированная версия метода ONC. Оба метода очень похожи. Так, данные по сети передаются в формате внещнего представления данных (XDR), а для утфощения разработки RPC-приложений применяется компилятор rpcgen. Отличие состоит в том, что интерфейсы прикладного программирования RPC на базе ONC основаны на гнездах, тогда как API RPC UNIX System V.4 могут использовать как гнезда, так и ТЫ. В этой главе рассматриваются приемы программирования RPC, поддерживаемые как методом ONC, так и методом UNIX System V.4. Большинство приведенных описаний относится к обоим методам. 12.1.1. Уровни интерфейса программирования RPC Существуют разные уровни интерфейса программирования RPC. Наивысший уровень обеспечивает пользователям возможность вызывать системные функции RPC так же, как библиотечные функции С (например, print/), а низший позволяет создавать RPC-программы с помощью API RPC. Рассмотрим уровни интерфейса программирования RPC подробнее. Интерфейс высшего уровня предоставляет пользователям возможность непосредственно вызывать системные функции RPC для сбора информации об удаленной системе. Эти функции можно использовать точно так же, как обычные библиотечные функции С, но при этом нужно указать специальные файлы заголовков, в которых объявляются прототипы этих функций, и связи между скомпилированными программами с помощью ключа -Irpcsvc. Объектный код этих библиотечных функций RPC содержится в библиотеке librpcsvc.a. Преимущество библиотечных функций RPC состоит в том, что они легче в использовании и требуют меньше усилий при программировании. Однако в системе определено лишь несколько таких функций, поэтому область их применения ограничена. Следующий уровень программирования RPC - это использование компилятора rpcgen для автоматического генерирования клиентских и серверных программ RPC. Пользователи должны написать только клиентские функции main (которые вызывают функции RPC) и серверные функции RPC. Компилятор rpcgen может генерировать и функции XDR, которые предназначены для преобразования используемых пользователем типов данных в формат XDR, необходимый для передачи информации между клиентом и сервером. Преимущество использования компилятора rpcgen в том, что пользователи могут сконцентрировать внимание на написании функций RPC и клиентских главных функций. Знать низкоуровневые API RPC не нужно. Благодаря этому сокращаются затраты на программирование и снижается количество ошибок. Но этот подход имеет и недостатки: пользователи не могут управлять параметрами средств передачи данных, которые используются клиентскими и серверными программами, созданными компилятором rpcgen. Они не могут также управлять динамически распределяемой памятью, которая применяется функциями XDR. Интерфейс низшего уровня обеспечивает создание клиентских и серверных программ RPC с помощью API RPC. Преимущество этого подхода заключается в том, что пользователи непосредственно управляют средствами передачи данных, которые применяются процессами, и динамически распределяемой памятью, используемой функциями XDR. Это, однако, требует дополнительных затрат, связанных с программированием. 12.2. Библиотечные функции RPC Заголовок библиотечных функций RPC - <фcsvc.h>. Каждый заголовок отвечает набору родственных библиотечных функций RPC и соответствующих функций XDR. Объектный код этих функций содержится в библиотеке librpcsvc.a в стандартном каталоге библиотек (например, /usr/lib). Ниже перечислены некоторые наиболее распространенные библиотечные функции RPC. Библиотечная функция ЛРС Няаи
Рассмотрим библиотечные функции на примере функции rstat, которая определяет время работы одной или нескольких удаленных систем (т.е. время с момента начальной зафузки системы до текущего момента). Кроме того, функция rstat собирает статистические данные об удаленной системе. Эта функция взаимодействует с демоном rc.rstatd, работающ1?м в удаленной системе, через механизм RPC: /* rstat.С: выдать время работы удаленных систем */ tinclude <iostream.h> tinclude <rpcsvc/rstat.h> extern С enum clnt stat rstat(char *host, struct statstime *statp); int main( int argc, char* argv[] ) struct statstime statv,-if (argc==l) ( cerr usage: argv[0] <host>. . .\n ; return 1} while [-argOO) { if [rstat(*++argv,sstatv)==RPC SUCCESS) [ int delta = statv.curtime.tv sec - statv.boottime.tv seci int hour = delta/3600,-int min = delta%3600,- cout * (*argv) * up hour hr. [min/60) min. [min%60) sec. endl; else perror( rstat ); return 0; В качестве аргумента командной строки эта программа принимает одно или несколько хост-имен систем. Для каждой из указанных систем процесс вызывает функцию rstat, которая собирает статистические данные. Эти данные помещаются в переменную statv, а рабочее время вычисляется путем вычитания значения statv.boottime.tvjsec из значения statv.curtime.tv sec. Тип данных struct statstime определяется в заголовке <rpcsvc/rstat.h>. В результате выполнения щнираммы может быть получена, например, следующая информация: % СС rstat.С -о rstat -Irpcsvc -Insl % rstat fruit lemon fruit up 1 hr. 12 min. 31 sec. lemon up 0 hr. 39 min. 24 sec. Как говорилось выше, пользоваться функциями RPC легко, а интерфейс программирования, который они предоставляют, подобен интерфейсу программирования библиотечных функций С. Однако число этих функций в системе ограничено, поэтому пользователям с помощью компилятора rpcgen или низшего уровня интерфейса профаммирования RPC приходится создавать для своих приложений дополнительные функции. 12.3. Компилятор rpcgen Компилятор rpcgen имеется в большинстве UNIX-систем. Он обеспечивает разработку приложений на базе RPC. Входной информацией для компилятора является написанный пользователем текстовый файл, в котором содержится следующая информация: номер профаммы RPC; один или несколько номеров версий профаммы RPC; один или несколько номеров процедур RPC (в RPC термины функция и процедура эквивалентны); определенные пользователем типы данных, передаваемых с помощью RPC. Для каждого из этих типов данных rpcgen автоматически создает функции XDR; С-код (не обязательно), который должен копироваться прямо в выходные файлы, генерируемые компилятором. Функция RPC обозначается номером профаммы, номером версии и номером процедуры. RPC-профамма соответствует одному серверному RPC-процессу, и этот процесс отвечает за выполнение от имени клиента всех необходимых процедур. Уровень обновления набора функций RPC задается номером RPC-версии - целым числом, которое должно начинаться с единицы. Номер RPC-процедуры - это уникальный идентификатор, присвоенный RPC-функции. Если существует несколько вариантов функции, то в обозначениях изменяется только номер версии, а номера профаммы и процедуры остаются без изменений. Номера процедур всех пользовательских функций RPC должны начинаться с единицы. Но всегда есть RPC-функция, номер процедуры которой в каждой RPC-профамме равен нулю. Эта функция может автоматически генерироваться компилятором rpcgen или задаваться пользователем. Она не принимает никаких аргументов и ничего не возвращает. Эта функция проверяет, существует ли серверный процесс. Рассмотрим, например, программу ;>n>i/.c: *г /* print.с */ , tinclude <iostream.h> finclude <fstream.h> int print( char* msg ) ( ofstream ofp( /dev/console ); if (ofp) ( ofp msg endl; ofp.close 0; return 1; return 0; int raain( int argc, char* argv[] ) ( while (-argc > 0) if (print(*++argv)) cout msg <<(*argv) delivered OK\n ; else cout msg (*argv) delivered failed\n ; return 0; После компиляции и выполнения этой программы получим следующие результаты: % СС print.с -о print % print Hello world Good-bye msg Hello world delivered OK msg Good-bye delivered OK Сообщения Hello world и Good-bye выводятся на системную консоль той мащины, где выполняется программа print. Чтобы преобразовать функцию print в удаленную процедуру, вручную создается файл print.x: I* файл print.x: это входной файл для rpcgen */ program PRINTPROG ( version PRINTVER ( int PRINT ( string ) = 1; ) = 1; ) = 0x20000001; В файле jjWnr.x функции nwt присвоены номер программы, номер версии и номер процедуры - 0x2000000001, 1 и 1 соответственно, program и в rpcgen - зарезервированные ключевые слова, а PRINTPROG, PRINTVER и PRINT - определенные пользователем макросы для этих номеров в контексте функции print. По соглащению эти константы обозначаются прописными буквами, но можно использовать и строчные. Обратите внимание на объявление прототипа функции print в print.x: тип формального аргумента определен как string, который представляет собой определенный в RPC тип данных, соответствующий символьной строке, заверщающейся NULL-символом. При помощи типа данных string механизм RPC различает данные типа символьных указателей от завершающихся нулем символьных массивов. Компилятор rpcgen обрабатывает файл print.x следующим образом: % Is print.x % rpcgen print.x % Is print.h print.x print clnt.c print svc.c Из файла print.X компилятор сгенерировал следующие три файла: Файл Назначение print.h Файл заголовка для клиентской и серверной программ print svc.c Серверная профамма без определения функции RFC print clnt.c Модуль клиентской профаммы. Содержит все интерфейсные функ- ции для вызова RPC-сервера Если входной файл для фс£еп называется <имя>.х, то соответствующие выходные файлы компилятора, как правило, получают имена <имя>.к, <UMH> svc.c W. <имя> с1ш.с. Заголовок print.h содержит объявление макросов PRINTPROG, PRINTVER и PRINT и прототип функции print. Файл print.h ддя приведенного выше файла print.x выглядит так: #ifndef fdefine #include ♦define tdefine fdefine PRINT H RPCGEN PRINT H RPCGEN <rpc/rpc.h> PRINTPROG PRINTVER extern int* print Kchar**, CLIENT*) ((unsigned long)(0x20000001) ((unsigned long)(1) ((unsigned long)(1) fendif /*! PRINT H RPCGEN*/ Обратите внимание на объявление функции print в файле print.h: имя функции представляет собой исходное имя, за которым следует знак подчеркивания и номер процедуры. Таким образом, RPC-имя функции print версии 1 - printl. Кроме того, возвращаемое значение функции print] указано как int*, а не как int. Это типично для RPC-функций: аргумент и возвращаемое значение каждой RPC-функции передаются по адресу, поэтому если локальная функция принимает аргумент типа char*, то ее RPC-партнер принимает аргумент типа char**. То же самое можно сказать и о возвращаемых
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |