на главную | войти | регистрация | DMCA | контакты | справка | donate |      

A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
А Б В Г Д Е Ж З И Й К Л М Н О П Р С Т У Ф Х Ц Ч Ш Щ Э Ю Я


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



Выполнение и возврат

6-8 Программа считывает входной аргумент и возводит его в квадрат. Результат сохраняется в структуре, адрес которой возвращается процедурой сервера. Поскольку мы возвращаем адрес переменной, эта переменная не может быть автоматической. Мы объявляем ее как статическую (static).

ПРИМЕЧАНИЕ

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

Откомпилируем клиент в системе Solaris, а сервер — в BSD/OS, запустим сервер, а затем клиент:

solaris % client bsdi 11

result: 121

solaris % client 209.75.135.35 22

result: 484

В первом случае мы указываем имя узла сервера, а во втором — его IP-адрес. Этим мы демонстрируем возможность использования как имен, так и IP-адресов для задания узла в функции clnt_create.

Теперь продемонстрируем некоторые ошибки, возникающие при работе clnt_create, если, например, не существует узел или на нем не запущена программа-сервер:

solaris % client nosuchhost 11

nosuchhost: RPC: Unknown host возвращается библиотекой RPC времени выполнения

clnt_create error             возвращается нашей функцией-оберткой

solaris % client localhost 11

localhost: rpc: program not registered

clnt_create error

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

Другая немаловажная деталь данного примера заключается в том, что в системах Sparc под Solaris и Intel x86 под управлением BSD/OS используется разный порядок байтов. В Sparc используется порядок big endian («тупоконечный»[2]), а в Intel — little endian («остроконечный») (что мы показали в разделе 3.4 [24]). Отличия в порядке байтов также обрабатываются библиотекой RPC времени выполнения автоматически с использованием стандарта XDR (внешнее представление данных), который мы обсудим в разделе 16.8.

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

solaris % rpcgen-Сsquare.x

solaris % cc-сclient.с-оclient.о

solaris % cc-сsquare_clnt.c-оsquare_clnt.o

solaris % cc-сsquare_xdr.с-оsquare_xdr.o

solaris % cc-оclient client.оsquare_clnt.o square_xdr.o libunpipc.a –lnsl

Параметр –С говорит rpcgen о необходимости создания прототипов функций ANSI С в заголовочном файле square.h. Программа rpcgen также создает заглушку клиента (client stub) в файле с именем square_clnt.с и файл с именем square_xdr.с, который осуществляет преобразование данных в соответствии со стандартом XDR. Наша библиотека (содержащая функции, используемые в этой книге) называется libunpipc.a, а параметр –lnsl подключает системную библиотеку сетевых функций в Solaris (включая библиотеки RPC и XDR времени выполнения).

Аналогичные команды используются для создания сервера, хотя rpcgen уже не нужно запускать снова. Файл square_svc.c содержит функцию main сервера, и файл square_xdr.о, обсуждавшийся выше, также требуется для работы сервера:

solaris % cc –с server.с –о server.о

solaris % сc –с square_svc.c –о square_svc.o

solaris % cc –о server server.о square_svc.o libunpipc.a –lnsl

При этом создаются клиент и сервер, выполняемые в системе Solaris.

Если клиент и сервер должны быть построены для разных систем (как в предыдущем примере, где клиент выполнялся в Solaris, а сервер — в BSD/OS), могут потребоваться дополнительные действия. Например, некоторые файлы должны быть либо общими (через NFS), либо находиться в обеих системах, а файлы, используемые клиентом и сервером (например, square_xdr.o), должны компилироваться в каждой системе в отдельности. 

UNIX: взаимодействие процессов

Рис. 16.1. Этапы создания приложения клиент-сервер с использованием RPC


На рис. 16.1 приведена схема создания приложения типа клиент-сервер. Три затемненных прямоугольника соответствуют файлам, которые мы должны написать. Штриховые линии показывают файлы, подключаемые через заголовочный файл square.h.

На рис. 16.2 изображена схема происходящего при удаленном вызове процедуры. Действия выполняются в следующем порядке:

1. Запускается сервер, который регистрируется в программе, управляющей портами на узле-сервере. Затем запускается клиент и вызывает clnt_create. Эта функция связывается с управляющей портами программой сервера и находит нужный порт. Функция clnt_create также устанавливает соединение с сервером по протоколу TCP (поскольку мы указали TCP в качестве используемого протокола в листинге 16.2). Мы не показываем эти шаги на рисунке и откладываем детальное обсуждение до раздела 16.3.

2. Клиент вызывает локальную процедуру, называемую заглушкой клиента. В листинге 16.2 эта процедура называлась squareproc_1, а файл, содержащий ее, создавался rpcgen автоматически и получал название square_clnt.c. С точки зрения клиента именно эта функция является сервером, к которому он обращается. Целью создания заглушки является упаковка аргументов для удаленного вызова процедуры, помещение их в стандартный формат и создание одного или нескольких сетевых сообщений. Упаковка аргументов клиента в сетевое сообщение называется сортировкой (marshaling). Клиент и заглушка обычно вызывают библиотеки функций RPC (clnt_create в нашем примере). При использовании редактора связей в Solaris эти функции загружаются из библиотеки –lnsl, тогда как в BSD/OS они входят в стандартную библиотеку языка С.

3. Сетевые сообщения отсылаются на удаленную систему заглушкой клиента. Обычно это требует локального системного вызова (например, write или sendto).

4. Сетевые сообщения передаются на удаленную систему. Для этого обычно используются сетевые протоколы TCP и UDP.

5. Заглушка сервера ожидает запросов от клиента на стороне сервера. Она рассортировывает аргументы из сетевых сообщений.

6. Заглушка сервера осуществляет локальный вызов процедуры для запуска настоящей функции сервера (процедуры squareproc_l_svc в листинге 16.3), передавая ей аргументы, полученные в сетевых сообщениях от клиента.

7. После завершения процедуры сервера управление возвращается заглушке сервера, которой передаются все необходимые значения.

8. Заглушка сервера преобразовывает возвращаемые значения к нужному формату и рассортировывает их в сетевые сообщения для отправки обратно клиенту.

9. Сообщения передаются по сети обратно клиенту. 

10. Заглушка клиента считывает сообщения из локального ядра (вызовом read или recvfrom).

11. После возможного преобразования возвращаемых значений заглушка клиента передает их функции клиента. Этот этап воспринимается клиентом как завершение работы процедуры.

UNIX: взаимодействие процессов

Рис. 16.2. Действия, происходящие при удаленном вызове процедуры


Аргументы процедуры | UNIX: взаимодействие процессов | История