- •Глава 11
- •В.Г.Олифер, н.А.Олифер. Сетевые операционные системы. Учебное пособие.-сПб.:бхв-Петербург, 2006.-536с.
- •В.А.Шеховцов. Операційні системи. Підручник .-к.:Виканавча група внv. 2005. 576с.
- •Столлингс в. Операционные системы. М.: Вильямс, 2001. -672с.
- •Раздел 11
- •11.1. Многопроцессорные системы
- •11.1.1. Типы многопроцессорных систем
- •11.1.2. Поддержка многопроцессорной в операционных системах
- •11.1.3. Производительность многопроцессорных систем
- •11.1.4. Планирование в многопроцессорных системах
- •11.1.5. Родство процессора
- •11.1.6. Поддержка многопроцессорности в Linux
- •11.1.7. Поддержка многопроцессорной в Windows xp
- •11.2. Принципы разработки распределенных систем
- •11.2.1. Отдалены вызовы процедур
- •11.2.2. Использование Sun rpc
- •11.2.3. Использование Microsoft rpc
- •11.2.4. Обработка ошибок и координация в распределенных системах
- •11.3. Распределеные файловые системы
- •11.3.1. Организация распределенных файловых систем
- •11.3.2. Файловая система nfs
- •11.3.3. Файловая система Microsoft dfs
- •11.4. Современные архитектуры распределенных систем
- •11.4.1. Кластерные системы
- •11.4.2. Grid-системы
- •Контрольные вопросы и задания
11.2.3. Использование Microsoft rpc
Разработка приложений с использованием Microsoft RPC основывается на тех же принципах, что и Sun RPC, но имеет некоторые особенности.
В первую очередь эта технология может использовать разные базовые средства связи (в частности TCP/IP и поіменовані каналы). Кроме того, возможна разработка клиентского приложения без явного задання соединения с сервером.
Разработка IDL-файла
Разработку приложения начинают с описания его интерфейсов на IDL.
Каждому интерфейсу ставят в соответствие универсальный уникальный идентификатор (UUID) -128-бітне число, генерирующее с помощью специального алгоритма, который обеспечивает высокую степень уникальности.
За этим идентификатором RPC-клиенты идентифицируют интерфейсы, экспортированные серверами.
Для создания UUID используют утилиту uuidgen.
Каждый интерфейс сопровождают атрибуты, перечисленные в квадратных дужках перед ключевым словом и interface:
-
uuid — UUID для этого интерфейса;
-
version — версия интерфейса;
-
auto_handle — значит, что клиентское применение не должно явно задавать код для установления соединения с сервером - это будет сделано из кода заглушки (есть и другие способы организации связи, например, при наличии атрибута implicitjiandle связь должна быть установлена явно).
Каждый параметр интерфейса тоже сопровождают атрибуты:
-
in, out - режим параметра (in - входной, out - выходной);
-
string — параметр нужно рассматривать как строка символов.
Приведем пример IDL-файла, который задает один интерфейс с одной процедурой. Дальше будем считать, что он называется mугрс. idl.
[uuid(c0579cff-e76a-417d-878b-1195d366385). version(l.O), auto_handle]
interface thello { /* определение интерфейса ihello */
void say_msg([in.string] unsigned char* msg);
}
IDL-файл обрабатывают IDL-компилятором (midl):
midl.exe /app_config myrpc.idl
Параметр /app_config задают в случае, когда в IDL-файле присутствуют атрибуты, которые касаются всего применения (в нашем случае это autojiandl e). Если его не указать, такие атрибуты задаются в отдельном файле с расширением .acf.
В результате обработки IDL-файла создадутся файлы заглушек для клиента и сервера (myrpc_c.c i myrpc_s.c), которые нужно скомпоновать в соответствующие выполняемые файлы, а также заглавный файл myrpc.h, что должен быть подключен в исходные файлы клиента и сервера.
Разработка отдаленных процедур
Отдаленные процедуры имеют такой вид, как и обычные. Отметим, что типы данных IDL отвечают типам языка С (а не типам Win32 АРI, таким как DWORD).
void say_msg(unsigned char* msg) { // код отдаленной процедуры
printf('от клиента: %s\n". msg);
}
Разработка сервера
В коде сервера в первую очередь нужно указать библиотеке поддержки RPC, какой протокол собирается использовать сервер и как идентифицировать сервер в соответствии с этим протоколом (какая его конечная точка - endpoint).
RPC_STATUS RPC_ENTRY RpcServerUseProtseqEp(unsigned char *prot.
unsigned int max_calls, unsigned char *endpoint, void *sec_desc);
где: prot - строка, которая определяет протокол ("ncacn_ip_tcp" - TCP/IP, "ncacn_np" -поіменовані каналы);
max_calls — максимальное количество соединений с сервером (значения по умолчанию задают как RPC_C_LISTEN_MAX_CALLS_DEFAULT);
endpoi nt — строка, которая определяет конечную точку (для TCP/IP он задает порт, для поименованных каналов — имя канала).
Эта функция возвращает статус RPC-вызова; если он равняется 0 (RPCS0K) — вызов завершился успешно. Аналогичный код возвращают и другие RPC-функции.
// сервер использует TCP/IP. прослушивает порт 5000
RpcServerUseProtseqEp("ncacn_ip_tcp". 5. "5000", NULL);
После задання протокола необходимо зарегистрировать интерфейсы в библиотеке поддержки RPC для того, чтобы клиенты могли его находить:
// для каждого интерфейса из IDL-файла
RpcServerRegisterIf(ihello_v1_0_s_ifspec. NULL. NULL);
Первым параметром задают структуру определения интерфейса, которую генерирует rnidl.
Имя такой структуры строят на основании имени интерфейса и его версии: имя_v1_0_s_іfspec.
Теперь клиенты смогут найти сервер, и можно перейти в режим ожидания соединений:
// ожидание соединений от клиентов
RpcServerListen(1, 5. FALSE);
Перед завершением работы сервер должен упразднить регистрацию своих интерфейсов в библиотеке поддержки
RpcServerUnregisterlf(NULL. NULL. FALSE);
Разработка клиента
Как отмечалось, в случае использования в IDL-файле атрибута auto_handl e в коде клиента не нужно явно задавать соединения с сервером. В этом случае код RPC-клиента может вообще не отличаться от кода применения, которое вызывает локальные процедуры. Но поскольку RPC-клиент обращается к отдаленным серверам, ошибки, которые могут возникать, должны обрабатываться особенным образом. Для организации обработки ошибок есть набор специальных макросов, которые реализуют обработку исключительных ситуаций в стиле языка C++: RpcTryExcept задает блок для проверки, RpcExcept - обработчик исключительной ситуации, RpcEndExcept завершает код обработки. Для определения кода ошибки в теле обработчика используют функцию RpcExceptionCodeO.
RpcTryExcept {
say_msg("he"l"lo"); // вызов отдаленной процедуры
}
RpcExcept(1) {
ргintf("ошибка RPC-вызова с кодом %d\п". RpcExceptionCode());
}
RpcEndExcept;
