Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ОС_Шеховцов_1.docx
Скачиваний:
74
Добавлен:
09.11.2019
Размер:
14.73 Mб
Скачать

20.2.3. Використання Microsoft rpc

Розробка застосувань із використанням Microsoft RPC ґрунтується на тих самих принципах, що і Sun RPC, але має деякі особливості [50]. Насамперед ця техно­логія може використовувати різні базові засоби зв'язку (зокрема TCP/IP та по-іменовані канали). Крім того, можлива розробка клієнтського застосування без явного задання з'єднання із сервером.

РозробкаIDL-файла

Розробку застосування починають з опису його інтерфейсів на IDL. Кожному інтер­фейсу ставлять у відповідність універсальний унікальний ідентифікатор (UUID) — 128-бітне число, генероване за допомогою спеціального алгоритму, що забезпечує високий ступінь унікальності. За цим ідентифікатором RPC-клієнти ідентифіку­ють інтерфейси, експортовані серверами. Для створення UUID використовують утиліту uuidgen.

Кожний інтерфейс супроводжують атрибути, перелічені у квадратних дужках перед ключовим словом interface:

♦uuid - UUID для цього інтерфейсу;

♦ version — версія інтерфейсу;

♦ auto handle - означає, що клієнтське застосування не повинне явно задавати код для встановлення з'єднання із сервером - це буде зроблено із коду за­глушки (є й інші способи організації зв'язку, наприклад, за наявності атрибу­та implicithandle зв'язок має бути встановлений явно).

Кожен параметр інтерфейсу теж супроводжують атрибути:

♦ in, out - режим параметра (in - вхідний, out - вихідний);

♦ string - параметр треба розглядати як рядок символів.

Наведемо приклад IDL-файла, що задає один інтерфейс з однією процедурою.

Далі вважатимемо, що він називається myrpc.idl.

[uuid(c0579cff-e76a-417d-878b-1195d366385). version(l.O). auto_handle]

interface ihello { /* визначення інтерфейсу ihello */

void say_msg([in,string] unsigned char* msg):

}

IDL-файл обробляють IDL-компілятором (midi):

midi.exe /app_config myrpc.idl

Параметр /appconfig задають y разі, коли в IDL-файлі присутні атрибути, що стосуються всього застосування (у нашому випадку це auto handle). Якщо його не вказати, такі атрибути задаються в окремому файлі з розширенням .acf.

Внаслідок обробки IDL-файла створяться файли заглушок для клієнта і сер­вера (myrpc_c.c і myrpc_s.c), які треба скомпонувати у відповідні виконувані фай­ли, а також заголовний файл myrpc.h, що має бути підключений у вихідні файли клієнта і сервера.

Розробка віддалених процедур

Віддалені процедури мають такий вигляд, як і звичайні. Зазначимо, що типи да­них IDL відповідають типам мови С (а не типам Win32 АРІ, таким як DWORD).

void say_msg(unsigned char* msg) { // код віддаленої процедури

printfC'Bifl клієнта: ïs\n". msg);

}

Розробка сервера

У коді сервера насамперед потрібно вказати бібліотеці підтримки RPC, який про­токол збирається використати сервер і як ідентифікувати сервер відповідно до Цього протоколу (яка його кінцева точка - endpoint).

RPC_STATUS RPCJNTRY RpcServerUseProtseqEp(unsigned char *prot.

unsigned int max_calls. unsigned char *endpoint. void *sec_desc);

де:prot - рядок, що визначає протокол ("ncacniptcp" - TCP/IP, "ncacnnp" -поіменовані канали);

max_calls - максимальна кількість з'єднань із сервером (значення за замовчу­ванням задають як RPC_C_LISTEN_MAX_CALLS_DEFAULT);

endpoint - рядок, що визначає кінцеву точку (для TCP/IP він задає порт, для поіменованих каналів — ім'я каналу).

Ця функція повертає статус RPC-виклику; якщо він дорівнює 0 (RPCS0K) -виклик завершився успішно. Аналогічний код повертають і інші RPC-функції.

// сервер використовує TCP/IP. прослуховує порт 5000 RpcServerUseProtseqEp("ncacn_ip_tcp". 5. "5000". NULL):

Після задання протоколу необхідно зареєструвати інтерфейси у бібліотеці під­тримки RPC для того, щоб клієнти могли його знаходити:

// для кожного інтерфейсу з IDL-файла RpcServerRegisterIf(77ie//o_vJ_0_s_ifspec. NULL. NULL);

Першим параметром задають структуру визначення інтерфейсу, яку генерує midi. Ім'я такої структури будують на підставі імені інтерфейсу і його версії:

і м'fl_vl_0_s_ifspec.

Тепер клієнти зможуть знайти сервер, і можна перейти в режим очікування з'єднань:

// очікування з'єднань від клієнтів RpcServerListent 1. 5. FALSE);

Перед завершенням роботи сервер має скасувати реєстрацію своїх інтерфей­сів у бібліотеці підтримки

RpcServerUnregisterIf(NULL. NULL. FALSE);

Розробка клієнта

Як зазначалося, у разі використання в IDL-файлі атрибута autohandle у коді клієн­та не потрібно явно задавати з'єднання із сервером. У цьому разі код RPC-клієнта може взагалі не відрізнятися від коду застосування, що викликає локальні проце­дури. Але оскільки RPC-клієнт звертається до віддалених серверів, помилки, які можуть виникати, мають оброблятися особливим чином. Для організації обробки помилок є набір спеціальних макросів, які реалізують обробку виняткових ситуа­цій у стилі мови C++: RpcTryExcept задає блок для перевірки, RpcExcept - оброблю­вач виняткової ситуації, RpcEndExcept завершує код обробки. Для визначення коду помилки в тілі оброблювача використовують функцію RpcExceptionCode().

RpcTryExcept {

say_msg("hello") : // виклик віддаленої процедури

RpcExcept(l) {

printfí"помилка RPC-виклику з кодом %d\n". RpcExceptionCodet));

}

RpcEndExcept;

Функції динамічного керування пам'яттю

Розробники RPC-застосувань мають включити у проект код двох функцій, що за­безпечують динамічний розподіл пам'яті: midl_user_allocate() і midl_user_free().

Вони автоматично викликаються із коду RPC-бібліотеки. Для їхньої реалізації зазвичай достатньо скористатися С-функціями mallocO і freeO.

void _RPCFAR * _RPCUSER midl_user_allocate(size_t size) {

return malloc(size);

}

void _RPC_USER midl_user_free(void* p) {

free(p):

}