Інтернет Windows Android

Протокол rpc. Видалені процедури: виклик віддалених процедур, визначення та особливості

Програми, які спілкуються через мережу, потребують механізму зв'язку. На нижньому рівні по надходженню пакетів подається сигнал, що обробляється мережевою програмою обробки сигналів. На верхньому рівні працює механізм rendezvous (рандеву), прийнятий у мові Ада. NFS використовує механізм виклику віддалених процедур (RPC), в якому клієнт взаємодіє з сервером (див. малюнок 1). Відповідно до цього процесу клієнт спочатку звертається до процедури, що надсилає запит на сервер. Після прибуття пакета із запитом сервер викликає процедуру його розтину, виконує запитувану послугу, посилає відповідь, і управління повертається клієнту.

Інтерфейс RPC можна уявити, що складається з трьох рівнів:

Верхній рівень повністю "прозорий". Програма цього рівня може, наприклад, містити звернення до процедури rnusers(), що повертає кількість користувачів віддаленої машині. Вам не потрібно знати про використання механізму RPC, оскільки ви робите звернення до програми.

Середній рівень призначений для загальних додатків. RPC-викликами на цьому рівні займаються підпрограми registerrpc() і callrpc(): registerrpc() отримує загальносистемний темний код, а callrpc() виконує виклик віддаленої процедури. Виклик rnusers() реалізується за допомогою цих двох підпрограм.

Нижній рівень використовується для більш складних завдань, що змінюють стандартні значення параметрів процедур. На цьому рівні ви можете явно маніпулювати гніздами, що використовуються для передачі повідомлень RPC.

Як правило, вам слід користуватися верхнім рівнем та уникати використання нижніх рівнів без особливої ​​необхідності.

Незважаючи на те, що в цьому посібнику ми розглядаємо інтерфейс тільки на Сі, звернення до віддалених процедур може бути зроблено з будь-якої мови. p align="justify"> Робота механізму RPC для організації взаємодії між процесами на різних машинах не відрізняється від його роботи на одній машині.

RPC (Remote Procedure Call, Сервіс виклику віддалених процедур) є інтерфейсом між віддаленими користувачами та певними програмами хоста, які запускаються за запитами цих користувачів. Сервіс RPC будь-якого хоста, як правило, надає клієнтам комплекс програм. Кожна з таких програм складається, своєю чергою, однією або кількома віддаленими процедурами. Наприклад, сервіс віддаленої файлової системи NFS, який побудований на викликах RPC, може складатися тільки з двох програм: наприклад, одна програма взаємодіє з високорівневими інтерфейсами користувача, а інша - з низькорівневими функціями введення-виводу.

У кожному виклик віддаленої процедури беруть участь дві сторони: активний клієнт, який надсилає запит виклику процедури на сервер, і сервер, який надсилає клієнту відповідь.

Примітка.Слід пам'ятати, що терміни " клієнт " і " сервер " у разі відносяться до певної транзакції Конкретний хост чи програмне забезпечення (процес чи програма) можуть працювати як у ролі клієнта, і у ролі сервера. Наприклад, програма, яка забезпечує роботу сервісу віддалених процедур, водночас може бути клієнтом у роботі з мережевою файловою системою.

Протокол RPC побудований на моделі викликів віддалених процедур, подібного механізму викликів локальних процедур. При виклику локальної процедури ви поміщаєте аргументи у певне місце пам'яті, у стек або змінні оточення і передаєте керування процесом за певною адресою. Після завершення роботи ви читаєте результати за конкретною адресою та продовжуєте свій процес.

У разі роботи з віддаленою процедурою, основна відмінність полягає в тому, що виклик віддаленої функції обслуговують два процеси: клієнтський процес та серверний процес.

Процес клієнта відправляє серверу повідомлення, в яке включені параметри процедури, що викликається, і очікує відповідного повідомлення з результатами її роботи. При отриманні відповіді результат зчитується і процес продовжує роботу. З боку сервера процес-обробник викликів перебуває в стані очікування, і при надходженні повідомлення зчитує параметри процедури, виконує її, відправляє відповідь і стає в стан очікування наступного виклику.

RPC-протокол не накладає жодних вимог на додаткові зв'язки між процесами і не вимагає синхронності виконуваних функцій, тобто виклики можуть бути асинхронними та взаємозалежними, так що клієнт під час очікування відповіді може виконувати інші процедури. Сервер RPC може виділяти для кожної функції окремий процес або віртуальну машину, тому, не чекаючи закінчення попередніх запитів, відразу ж може приймати наступні.

Проте між викликами локальних та віддалених процедур є кілька важливих відмінностей:

1. Обробка помилок.Клієнт у будь-якому випадку повинен отримувати повідомлення про помилки, що виникають при викликах віддалених процедур на сервері або мережі.

2. Світові змінні.Оскільки сервер не має доступу до адресного простору клієнта, при викликах віддалених процедур не можна використовувати приховані параметри у вигляді глобальних змінних.

3. Продуктивність.Швидкість виконання віддалених процедур, як правило, на один або два порядки нижче швидкості виконання аналогічних локальних процедур.

4. Аутентифікація.Оскільки виклики віддалених процедур відбуваються через мережу, необхідно використовувати механізми автентифікації клієнта.

Принципи побудови протоколу.

Протокол RPC може використовувати кілька транспортних протоколів. До обов'язків RPC-протоколу входить лише забезпечення стандартів та інтерпретація передачі повідомлень. Достовірність та надійність передачі повідомлень повністю забезпечується транспортним рівнем.

Однак, RPC може контролювати вибір і деякі функції транспортного протоколу. Як приклад взаємодії між RPC та транспортним протоколом розглянемо процедуру призначення RPC-порту роботи прикладного процесу через RPC - Portmapper.

Ця функція динамічно (за запитом) призначає для з'єднання RPC певний порт. Функція Portmapperвикористовується досить часто, оскільки набір зарезервованих для RPC транспортних портів обмежений, а кількість процесів, які можуть одночасно працювати дуже високо. Portmapperнаприклад, викликається при виборі портів взаємодії клієнта та сервера системи NFS.

Сервіс Portmapperвикористовує механізм широкомовних повідомлень RPC на певний порт - ІІІ. Цей порт клієнт надсилає широкомовне повідомлення запиту порту певного сервісу RPC. Сервіс Portmapperобробляє таксі повідомлення, визначає адресу локального сервісу RPC та надсилає клієнту відповідь. Сервіс RPC Portmapperможе працювати як з TCP, і з UDP-протоколами.

RPC може працювати з різними транспортними протоколами, але ніколи не дублює їх функції, тобто якщо RPC працює поверх TCP, всі турботи про надійність та достовірність з'єднання RPC покладається на TCP. Проте, якщо протокол RPC встановлено на UDP, він може забезпечувати додаткові власні функції забезпечення гарантованої доставки повідомлень.

Примітка.Прикладні завдання можуть розглядати протокол RPC як певну процедуру виклику функції по мережі JSR (Jump Subroutine Instruction).

Для роботи RPC-протоколу необхідно виконання наступних умов:

1. Унікальна ідентифікація всіх видалених процедур на даному хості. RPC-запити містять три поля ідентифікаторів – номер віддаленої програми (сервісу), номер версії віддаленої програми та номер віддаленої процедури зазначеної програми. Номер програми призначається виробником сервісу, номер процедури вказує на конкретну функцію цього сервісу

2. Ідентифікація версії протоколу RPC. Повідомлення RPC містять поле версії протоколу RPC. Вона використовується для узгодження форматів параметрів, що передаються при роботі клієнта з різними версіями RPC.

3. Надання механізмів автентифікації клієнта на сервері. RPC-протокол забезпечує процедуру аутентифікації клієнта в сервісі, і, у разі потреби, при кожному запиті або надсиланні відповіді клієнту. Крім того, RPC дозволяє використовувати різноманітні додаткові механізми безпеки.

RPC може використовувати чотири типи механізмів аутентифікації:

AUTH_NULL - без використання аутентифікації

AUTH_UNIX - автентифікація за стандартом UNIX

AUTH_SHORT - автентифікація за стандартом UNIX із власною структурою кодування

AUTH_DES - автентифікація за стандартом DES

4. Ідентифікація повідомлень відповіді відповідні запити. Повідомлення RPC містять ідентифікатор запиту, на підставі якого вони були побудовані. Цей ідентифікатор можна назвати ідентифікатором транзакції виклику RPC. Даний механізм особливо необхідний під час роботи в асинхронному режимі та при виконанні послідовності з декількох RPC-дзвінків.

5. Ідентифікація помилок роботи протоколу. Усі мережні або серверні помилки мають унікальні ідентифікатори, за якими кожен із учасників з'єднання може визначити причину збою в роботі.

Структури повідомлень протоколу

При передачі RPC-повідомлень поверх транспортного протоколу, кілька RPC-повідомлень можуть розташовуватися всередині одного транспортного пакета. Щоб відокремлювати одне повідомлення від іншого, використовується маркер запису (RM - Record Marker). Кожне RPC-повідомлення "маркується" рівно одним RM.

RPC-повідомлення може складатися з кількох фрагментів. Кожен фрагмент складається з чотирьох байт заголовка та (від 0 до 2**31-1) даних. Перший біт заголовка вказує, чи є даний фрагмент останнім, інші 31 біт вказують довжину пакета даних.

Структура RPC формально описана на мові опису та подання форматів даних - XDR з доповненнями, що стосуються опису процедур. Можна сказати, що мова опису RPC є розширенням XDR, доповненим роботою з процедурами.

Структура RPC-пакету виглядає так:

struct rpc_msg (

unsigned int xid;

union switch (msg_type mtype) (

call_body cbody;

reply body rbody;

де xid – ідентифікатор поточної транзакції, call_body – пакет запиту, reply_body – пакет відповіді. Структура запиту виглядає приблизно так:

struct call body (

unsigned int rpcvers;

unsigned int prog;

unsigned int vers;

unsigned int proc;

opaque_auth cred;

opaque_auth verf;

/* procedure parameters */

Структура відповіді (reply_body) може містити або структуру, що передається у разі помилки (тоді вона містить код помилки), або структуру успішної обробки запиту (тоді вона містить дані, що повертаються).

Інтерфейс високого рівня.

Використання підпрограм у програмі - традиційний спосіб структурувати завдання, зробити його більш ясним. Підпрограми, що найчастіше використовуються, збираються в бібліотеки, де можуть використовуватися різними програмами. В даному випадку йдеться про локальний (місцевий) виклик, тобто і викликає, і об'єкти, що викликається, працюють в рамках однієї програми на одному комп'ютері.

У разі віддаленого виклику процес, що виконується на одному комп'ютері, запускає процес на віддаленому комп'ютері (тобто фактично запускає код процедури на віддаленому комп'ютері). Очевидно, що віддалений виклик процедури істотно відрізняється від традиційного локального, проте з точки зору програміста такі відмінності практично відсутні, тобто архітектура віддаленого виклику процедури дозволяє зімітувати виклик локальної.

Однак якщо у випадку локального виклику програма передає параметри в виклик, що викликається і отримує результат роботи через стек або загальні області пам'яті, то у разі віддаленого виклику передача параметрів перетворюється на передачу запиту по мережі, а результат роботи знаходиться в відгуку, що прийшов.

Цей підхід є можливою основою створення розподілених додатків, і хоча багато сучасних систем не використовують цей механізм, основні концепції та терміни у багатьох випадках зберігаються. При описі механізму RPC ми будемо традиційно називати процес - клієнтом, а віддалений процес, що реалізує процедуру, - сервером.

Видалений виклик процедури включає такі кроки:

1. Програма-клієнт здійснює локальний виклик процедури, яка називається заглушкою (stub). При цьому клієнту "здається", що викликаючи заглушку, він здійснює власне виклик процедури-сервера. клієнт передає заглушці необхідні параметри, а вона повертає результат. Однак справа не зовсім так, як це собі уявляє клієнт. Завдання заглушки - прийняти аргументи, призначені для віддаленої процедури, можливо, перетворити їх на якийсь стандартний формат і сформувати мережевий запит. Упаковка аргументів та створення мережного запиту називається збиранням (marshalling).

2. Мережевий запит надсилається по мережі на віддалену систему. Для цього у заглушці використовуються відповідні дзвінки, наприклад, розглянуті у попередніх розділах. Зауважимо, що у своїй можуть бути використані різні транспортні протоколи, причому як сімейства TCP/IP.

3. На віддаленому хості все відбувається у зворотному порядку. Заглушка сервера чекає на запит і при отриманні витягує параметри - аргументи виклику процедури. Вилучення (unmarshalling) може містити необхідні перетворення (наприклад, зміни порядку розташування байтів).

4. Заглушка виконує виклик цієї процедури-сервера, якій адресовано запит клієнта, передаючи їй отримані через мережу аргументи.

5. Після виконання процедури керування повертається в заглушку сервера, передаючи їй потрібні параметри. Як і заглушка клієнта; заглушка сервера перетворює повернені процедурою значення, формуючи мережеве повідомлення-відгук, який передається через мережу системі, від якої надійшов запит.

6. Операційна система передає отримане повідомлення заглушці клієнта, яка, після необхідного перетворення, передає значення (що є значеннями, повернутими віддаленої процедурою) клієнту, який це як нормальне повернення з процедури.

Таким чином, з точки зору клієнта, він робить виклик віддаленої процедури, як він це зробив би для локальної. Те саме можна сказати і про сервер: виклик процедури відбувається стандартним чином, якийсь об'єкт (заглушка сервера) здійснює виклик локальної процедури і отримує повернені нею значення. Клієнт сприймає заглушку як викликану процедуру-сервер, а сервер приймає власну заглушку за клієнта.

Таким чином, заглушки складають ядро ​​системи RPC, відповідаючи за всі аспекти формування та передачі повідомлень між клієнтом та віддаленим сервером (процедурою), хоча клієнт і сервер вважають, що виклики відбуваються локально. У цьому полягає основна концепція RPC - повністю сховати розподілений (мережевий) характер взаємодії в коді заглушок. Переваги такого підходу очевидні: і клієнт та сервер є незалежними від мережевої реалізації, обидва вони працюють у рамках певної розподіленої віртуальної машини, і виклики процедур мають стандартний інтерфейс.

Передача параметрів

Передача параметрів-значень не викликає особливих труднощів. У цьому випадку заглушка клієнта розміщує значення параметра в мережевому запиті, можливо, виконуючи перетворення до стандартного вигляду (наприклад, змінюючи порядок слідування байтів). Набагато складніше справа з передачею покажчиків, коли параметр є адресою даних, а чи не їх значення. Передача у запиті адреси позбавлена ​​сенсу, оскільки віддалена процедура виконується зовсім іншому адресному просторі. Найпростішим рішенням, що застосовується в RPC, є заборона клієнтам передавати параметри інакше, як за значенням, хоча це безумовно накладає серйозні обмеження.

Зв'язування (binding)

Перш ніж клієнт зможе викликати віддалену процедуру, необхідно пов'язати його з віддаленою системою, що має в своєму розпорядженні необхідний сервер. Таким чином, завдання зв'язування розпадається на дві:

Знаходження віддаленого хоста з сервером

Знаходження необхідного серверного процесу на даному хості

Для знаходження хоста можна використовувати різні підходи. Можливий варіант - створення якогось централізованого довідника, в якому хости анонсують свої сервери, і де клієнт за бажання може вибрати хост і адресу процедури, що підходять для нього.

Кожна процедура RPC однозначно визначається номером програми та процедури. Номер програми визначає групу віддалених процедур, кожна з яких має власний номер. Кожній програмі також надається номер версії, тому при внесенні в програму незначних змін (наприклад, при додаванні процедури) відсутня необхідність змінювати її номер. Зазвичай кілька функціонально схожих процедур реалізуються в одному програмному модулі, який при запуску стає сервером цих процедур, і який ідентифікується номером програми.

Таким чином, коли клієнт хоче викликати віддалену процедуру, йому необхідно знати номери програми, версії та процедури, що надає потрібний сервіс.

Для передачі запиту клієнту також необхідно знати мережеву адресу хоста та номер порту, пов'язаний із програмою-сервером, що забезпечує потрібні процедури. Для цього використовується демон portmap(IM) (у деяких системах він називається rpcbind(IM)). Демон запускається на хості, який надає сервіс віддалених процедур, та використовує загальновідомий номер порту. При ініціалізації процесу-сервера він реєструє в portmap(IM) свої процедури та номери портів. Тепер, коли клієнту потрібно знати номер порту для виклику конкретної процедури, він надсилає запит на сервер portmap(IM), який, своєю чергою, або повертає номер порту, або перенаправляє запит безпосередньо серверу віддаленої процедури і після виконання повертає клієнту відгук. У будь-якому випадку, якщо потрібна процедура існує, клієнт отримує від сервера portmap(IM) номер порту процедури, і подальші запити може робити безпосередньо на цей порт.

Обробка спеціальних ситуацій (exception)

Обробка особливих ситуацій при виклику локальних процедур не є особливою проблемою. UNIX забезпечує обробку помилок процесів, таких як розподіл на нуль, звернення до неприпустимої області пам'яті і т. д. У разі виклику віддаленої процедури ймовірність виникнення помилкових ситуацій збільшується. До помилок сервера та заглушок додаються помилки, пов'язані, наприклад, з отриманням помилкового повідомлення мережі.

Наприклад, при використанні UDP як транспортний протокол проводиться повторна передача повідомлень після певного тайм-ауту. Клієнту повертається помилка, якщо, через кілька спроб, відгук від сервера так і не був отриманий. У випадку, коли використовується протокол TCP, клієнт повертає помилку, якщо сервер обірвав TCP-з'єднання.

Семантика виклику

Виклик локальної процедури однозначно призводить до її виконання, після чого управління повертається в головну програму. Інакше справа при виклику віддаленої процедури. Неможливо встановити, коли конкретно виконуватиметься процедура, чи буде вона виконана взагалі, а якщо буде, то скільки разів? Наприклад, якщо запит буде отримано віддаленою системою після аварійного завершення програми сервера, процедура не буде виконана взагалі. Якщо клієнт при неотриманні відгуку після певного проміжку часу (тайм-ауту) повторно надсилає запит, може виникнути ситуація, коли відгук вже передається по мережі, а повторний запит знову приймається на обробку віддаленої процедурою. В цьому випадку процедуру буде виконано кілька разів.

Таким чином, виконання віддаленої процедури можна характеризувати наступною семантикою:

- Один і лише один раз.Даної поведінки (у деяких випадках найбільш бажаної) важко вимагати через можливі аварії сервера.

- Максимум разів.Це означає, що процедура або взагалі не була виконана, або була виконана лише один раз. Подібне твердження можна зробити при отриманні помилки замість нормального відгуку.

- Хоча б раз.Процедура, напевно, була виконана один раз, але можливо і більше. Для нормальної роботи в такій ситуації віддалена процедура повинна мати властивість ідемпотентності (від англ. idemponent). Ця властивість має процедуру, багаторазове виконання якої не викликає кумулятивних змін. Наприклад, читання файлу ідемпотентно, а додавання тексту до файлу - ні.

Подання даних

Коли клієнт та сервер виконуються в одній системі на одному комп'ютері, проблем із несумісністю даних не виникає. І для клієнта і для сервера дані у двійковому вигляді надаються однаково. У разі віддаленого виклику справа ускладнюється тим, що клієнт і сервер можуть виконуватися на системах з різною архітектурою, що мають різне представлення даних (наприклад, представлення значення плаваючою точкою, порядок слідування байтів і т. д.)

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

Наприклад, формат представлення даних у RPC фірми Sun Microsystems наступний:

Порядок прямування байтів - Старший - останній

Подання значень з плаваючою точкою - IEEE

Подання символу - ASCII

За своєю функціональністю система RPC займає проміжне місце між рівнем програми та транспортним рівнем. Відповідно до моделі OSI цьому положенню відповідають рівні представлення та сеансу. Таким чином, RPC теоретично незалежний від реалізації мережі, зокрема від мережевих протоколів транспортного рівня.

Програмні реалізації системи зазвичай підтримують один або два протоколи. Наприклад, система RPC розробки фірми Sun Microsystems підтримує передачу повідомлень із використанням протоколів TCP та UDP. Вибір того чи іншого протоколу залежить від вимог програми. Вибір протоколу UDP виправданий для додатків, які мають такі характеристики:

Процедури, що викликаються, ідемпотентні

Розмір переданих аргументів і результату, що повертається менше розміру пакета UDP - 8 Кбайт.

Сервер забезпечує роботу з кількома сотнями клієнтів. Оскільки під час роботи з протоколами TCP сервер змушений підтримувати з'єднання з кожним активних клієнтів, це займає значну частину його ресурсів. Протокол UDP щодо цього є менш ресурсоємним

З іншого боку, TCP забезпечує ефективну роботу програм з наступними характеристиками:

Додаток потребує надійного протоколу передачі

Процедури, що викликаються, неідепонентні

Розмір аргументів або результату, що повертається, перевищує 8 Кбайт

Вибір протоколу зазвичай залишається за клієнтом, і система по-різному організовує формування та передачу повідомлень. Так, при використанні протоколу TCP, для якого передані дані є потік байтів, необхідно відокремити повідомлення один від одного. Для цього наприклад, застосовується протокол маркування записів, описаний RFC1057 "RPC: Remote Procedure Call Protocol specification version 2", при якому на початку кожного повідомлення міститься 32-розрядне ціле число, що визначає розмір повідомлення в байтах.

По-різному і справа з семантикою виклику. Наприклад, якщо RPC виконується за допомогою ненадійного транспортного протоколу (UDP), система виконує повторну передачу повідомлення через короткі проміжки часу (тайм-аути). Якщо програма-клієнт не отримує відгук, то з упевненістю можна сказати, що процедура була виконана нуль або більше разів. Якщо відгук був отриманий, програма може зробити висновок, що процедура була виконана хоча б одного разу. При використанні надійного транспортного протоколу (TCP) у разі отримання відгуку можна сказати, що процедуру було виконано один раз. Якщо ж відгук не отримано, точно сказати, що процедура виконана була, нельзя3.

Як це працює?

По суті, власне система RPC є вбудованою у програму-клієнт та програму-сервер. Втішно, що при розробці розподілених додатків не доведеться вникати в подробиці протоколу RPC або програмувати обробку повідомлень. Система передбачає існування відповідного середовища розробки, що значно полегшує життя творцям прикладного програмного забезпечення. Одним з ключових моментів в RPC є те, що розробка розподіленої програми починається з визначення інтерфейсу об'єкта - формального опису функцій сервера, зробленого спеціальною мовою. На основі цього інтерфейсу автоматично створюються заглушки клієнта і сервера. Єдине, що потрібно зробити після цього, - написати фактичний код процедури.

Як приклад розглянемо RPC фірми Sun Microsystems. Система складається із трьох основних частин:

Rpcgen(1) - RPC-компілятор, який на підставі опису інтерфейсу віддаленої процедури генерує заглушки клієнта та сервера у вигляді програм мовою С.

Бібліотека XDR (eXternal Data Representation), яка містить функції для перетворення різних типів даних у машинно-незалежний вигляд, що дозволяє проводити обмін інформацією між різнорідними системами.

Бібліотека модулів, які забезпечують роботу системи загалом.

Розглянемо приклад найпростішого розподіленого додатка для ведення журналу подій. Клієнт викликає віддалену процедуру запису повідомлення у файл журналу віддаленого комп'ютера.

Для цього доведеться створити як мінімум три файли: специфікацію інтерфейсів віддалених процедур log.x (мовою опису інтерфейсу), власне текст віддалених процедур log.c і текст головної програми клієнта main() - client.c (мовою С).

Компілятор rpcgen(l) на підставі специфікації log.x створює три файли: текст заглушок клієнта та сервера мовою С (log clnt.c і log svc.c) та файл описів log.h, використовуваний обома заглушками.

Розглянемо вихідні тексти програм.

У цьому файлі вказуються реєстраційні параметри віддаленої процедури - номери програми, версії та процедури, а також визначається інтерфейс виклику - вхідні аргументи та значення, що повертаються. Таким чином, визначено процедуру RLOG, яка як аргумент приймає рядок (яка буде записана в журнал), а значення, що повертається стандартно вказує на успішне або невдале виконання замовленої операції.

program LOG_PROG (

version LOG_VER (

int RLOG (string) = 1;

) = 0х31234567;

Компілятор rpcgen(l) створює файл заголовків log.h, де, зокрема, визначено процедури:

log.h

* Please do not edit this file.

* It was generated using rpcgen.

#ifndef _LOG_H_RPCGEN

#define _LOG_H_RPCGEN

#include

/* Номер програми*/

#define LOG_PROG ((unsigned long) (0х31234567))

#define LOG_VER ((unsigned long) (1)) /*Номер версії*/

#define RLOG ((unsigned long) (1)) /*Номер процедури*/

extern int *rlog_l();

/*Внутрішня процедура - нам її використовувати не доведеться*/ extern int log_prog_l_freeresult();

#endif /* !_LOG_H_RPCGEN */

Розглянемо цей файл уважно. Компілятор транслює ім'я RLOG визначене у файлі опису інтерфейсу, в rlog_1, замінюючи великі символи на малі та додаючи номер версії програми з підкресленням. Тип значення, що повертається змінився з int на int *. Таке правило - RPC дозволяє передавати та отримувати лише адреси оголошених в описі інтерфейсу параметрів. Це ж правило стосується і рядка, що передається як аргумент. Хоча з файлу print.h це не випливає, насправді як аргумент функції rlog_l () також передається адреса рядка.

Крім файлу заголовків компілятор rpcgen(l) створює модулі заглушки клієнта та заглушки сервера. По суті, текст цих файлів містить весь код віддаленого виклику.

Заглушка сервера є головною програмою, що обробляє всю мережеву взаємодію із клієнтом (точніше, з його заглушкою). Для виконання операції заглушка сервера здійснює локальний виклик функції, текст якої необхідно написати:

log.c

#include

#include

#include

#include "log.h"

int *rlog_1 (char **arg)

/*Повертане значення має визначатися як static*/

static int result;

int fd; /*Файловий дескриптор журналу*/

/*0ткроем файл журналу (створимо, якщо він не існує), у разі невдачі повернемо код помилки result == 1.*/

if ((fd=open("./server .log",

O_CREAT | O_RDWR | O_APPEND))< 0) return (&result);

len = strlen (* arg);

if (write(fd, *arg, strlen(*arg)) != len)

return(&result); /*Повертаємо результат - адреса result*/

Заглушка клієнта приймає аргумент, що передається віддаленій процедурі, робить необхідні перетворення, формує запит на сервер portmap(1M), обмінюється даними із сервером віддаленої процедури і, нарешті, передає значення клієнту. Для клієнта виклик віддаленої процедури зводиться до виклику заглушки і не відрізняється від звичайного локального виклику.

client.c

#include

#include "log.h"

main(int argc, char *argv)

char *server, *mystring, *clnttime;

if (argc != 2) (

fprintf(stderr, "Формат виклику: %s Адреса_хоста\n",

/*Отримаємо дескриптор клієнта. У разі невдачі - повідомимо про

неможливості встановлення зв'язку із сервером*/

if ((с1 = clnt_create (server,

LOG_PROG, LOG_VER, "udp")) == NULL) (

clnt_pcreateerror (server);

/*Виділимо буфер для рядка*/

mystring = (char *) malloc (100);

/*Визначимо час події*/

bintime = time ((time_t *) NULL);

clnttime = ctime(&bintime);

sprintf (mystring, "%s - Клієнт запущено", clnttime);

/*Передамо повідомлення для журналу – час початку роботи клієнта. У разі невдачі – повідомимо про помилку*/

if ((result = rlog_l(&mystring, cl)) == NULL) (

fprintf(stderr, "error2\n");

clnt_perror(cl, server);

/*B у разі невдачі на віддаленому комп'ютері повідомимо про помилку*/

if (*result !=0)

fprintf(stderr, "Помилка запису журнал\n");

/*0вільним дескриптор*/

cint destroy(cl);

Заглушка клієнта log_clnt.c компілюється з модулем client.c для отримання програми клієнта.

cc -про rlog client.c log_clnt.c -Insl

Заглушка сервера log_svc.c і процедура log.c компілюються для отримання програми сервера, що виконується.

cc -про logger log_svc.c log.c -Insl

Тепер на деякому хості server.nowhere.ru необхідно запустити серверний процес:

Після чого при запуску клієнта rlog на іншій машині сервер додасть відповідний запис файлу журналу.

Схема роботи RPC у разі наведено на рис. 1. Модулі взаємодіють так:

1. Коли запускається серверний процес, він створює сокет UDP і пов'язує будь-який локальний порт із цим сокетом. Далі сервер викликає бібліотечну функцію svc_register(3N) для реєстрації номерів програми та її версії. Для цього функція звертається до процесу portmap(IM) та передає необхідні значення. Сервер portmap(IM) зазвичай запускається під час ініціалізації системи та зв'язується з деяким загальновідомим портом. Тепер portmap(3N) знає номер порту для нашої програми та версії. Сервер ж очікує на отримання запиту. Зауважимо, що всі описані дії виконуються заглушкою сервера, створеної компілятором rpcgen(IM).

2. Коли запускається програма rlog, перше, що вона робить – викликає бібліотечну функцію clnt_create(3N), вказуючи їй адресу віддаленої системи, номери програми та версії, а також транспортний протокол. Функція надсилає запит на сервер portmap(IM) віддаленої системи server.nowhere.m і отримує номер віддаленого порту для сервера журналу.

3. Клієнт викликає процедуру rlog_1 (), визначену в заглушці клієнта, і передає управління заглушці. Та, своєю чергою, формує запит (перетворюючи аргументи у формат XDR) як пакета UDP і спрямовує їх у віддалений порт, отриманий від сервера portmap(IM). Потім вона деякий час чекає на відгук і у разі неотримання повторно відправляє запит. При сприятливих обставинах запит приймається сервером logger (модулем заглушки сервера). Заглушка визначає, яка саме функція була викликана (за номером процедури), та викликає функцію rlog_1() модуля log.c. Після повернення керування назад в заглушку остання перетворює повернене функцією rlog_1 () значення формату XDR, і формує відгук також у вигляді пакета UDP. Після отримання відгуку заглушка клієнта отримує повернення, перетворює його і повертає в головну програму клієнта.


До складу операційної системи Windows будь-якої модифікації починаючи з версії ХР входить службовий компонент, що позначається як RPC. Що це таке, рядові користувачі здебільшого не знають, тим більше, не здогадуються, для чого потрібна ця служба і як вона працює. У зв'язку з цим пропонується розглянути деякі основні аспекти, пов'язані із самим компонентом, принципами його роботи та сферою використання без опису непотрібних та складних технічних термінів. Окремо зупинимося на можливих помилках служби та методиках їхнього швидкого усунення.

Видалені процедури (виклик віддалених процедур): що таке?

Очевидно, багато користувачів, виходячи з назви цього службового компонента, вже зробили висновок у тому, що таке. Дійсно, видалені процедури (виклик віддалених процедур) мають на увазі якісь дії при виконанні їх не на локальному комп'ютері, а на віддаленому (найчастіше на сервері).

Тобто запит формується однією терміналі, потім передається на інший, де й виконується, після чого перший комп'ютер повертається відповідь (звіт) про виконання. Але це лише примітивне пояснення. Насправді все набагато складніше, оскільки тут потрібно враховувати протоколи передачі даних (UDP, TCP, HTTP) і багато інших механізмів.

Навіщо потрібна ця служба?

Незважаючи на основне призначення, віддалений виклик процедур RPC може застосовуватись не на різних комп'ютерах, а на одному. Як найпростіший приклад можна навести виклик якоїсь функції однієї програми з іншої програми. Багато музикантів, що працюють з віртуальними студіями і секвенсорами, знають, що в кожному такому додатку є власний модуль редагування або обробки аудіо, який не завжди відповідає вимогам, що висуваються користувачем. І будь-яка студія дозволяє замість нього підключити будь-яку іншу зовнішню програму.

Наприклад, у налаштуваннях секвенсора FL Studio можна вказати іншу програму (скажімо, Adobe Audition), яка для редагування звукових файлів (семплів) у середовищі основної програми буде використовуватись за замовчуванням. При цьому підключення Adobe Audition до FL Studio буде здійснюватись не через віртуальні хости на зразок VST, RTAS або DX, а безпосередньо через задіяння служби віддаленого виклику процедур. Зрозуміло, що це приклад не єдиний, оскільки область застосування описуваного компонента набагато ширше.

Дуже часто цю службу пов'язують ще з розподілом обчислювального навантаження на термінали, між якими встановлюється інтерактивний зв'язок. При цьому, якщо здійснюється рівномірний розподіл навантаження на обчислювальні ресурси кількох комп'ютерів, досягти максимальної продуктивності можна лише за умови обміну невеликими обсягами даних та швидким відгуком між компонентами.

Збій під час віддаленого виклику процедури: у чому причина?

На жаль, через таку затребуваність, поява збоїв та помилок, пов'язаних з цією службою, – досить часте явище.

У результаті стає неможливим як використання самого компонента. Іноді навіть не вдається отримати доступ до деяких системних налаштувань, а Windows ХР так і зовсім злітає, після чого відновити її до нормального працездатного стану буває досить проблематично. Ще одна проблема – інструмент онлайн-відновлення DISM, що входить до складу операційної системи.

Саме з порушеннями в роботі пов'язують появу помилки 1726, яка безпосередньо впливає і на функціонування компонентів служби RPC.

Основними причинами таких збоїв називають виклик засобів перевірки або відновлення системи, коли DISM активний або не може коректно завершити роботу (наприклад, при одночасному старті з двох командних консолей інструментів DISM і SFC); коли служба працює паралельно із обслуговуванням компонентів RPC; коли служба блокується антивірусним програмним забезпеченням

Таким чином, якщо спостерігається збій при віддаленому виклику процедур у Windows 7 і вище, перше, що потрібно зробити – завершити роботу DISM, перезавантажити комп'ютер та запустити службу заново. Якщо це не допоможе, можна спробувати перейти в безпечний режим і повністю відключити антивірусний захист на час проведення відновлення. На додаткових заходах, які допомагають виправити будь-який збій при віддаленому виклику процедури та в будь-якій модифікації Windows, зупинимося окремо. Поки ж подивимося на питання, пов'язані з відключенням цього системного компонента (на жаль, багато користувачів, які не знають суті питання, намагаються займатися саме такими речами).

Чи можна вимкнути службу RPC?

Отже, давайте подивимося, як реально деактивувати виклик віддалених процедур. Видалені процедури, виходячи з рекомендацій розробників, не можна відключати в жодному разі. Це важливо! В принципі сама зробити цього не дозволить. Є, звичайно, деякі обхідні шляхи, що мають на увазі використання додаткового програмного забезпечення, але зі зрозумілих причин, назви таких додатків не наводяться, оскільки при їх неправильному використанні вся система може стати непридатною.

Наслідки відключення процесів RPC

Навіть якщо користувачеві вдасться якимось чином відключити видалені процедури (виклик віддалених процедур), наслідки, на жаль, можуть бути непередбачуваними. Як уже говорилося, Windows XP може взагалі перестати працювати, а в ОС рангом вище, як наслідок, може з'явитися величезна кількість системних збоїв, які усунути не вдасться хоча б через відсутність доступу до критично важливих налаштувань і параметрів Windows, причому навіть у безпечному режимі або при старті зі знімного носія. Тим не менш, збій при виклику віддалених процедур у Windows 10 або ранніх версіях операційної системи виправити можна. Метод не найпростіший, тому за його використання потрібно бути дуже уважним.

Вимкнення локатора віддаленого доступу

Отже, основну службу RPC не можна відключати. Але, можливо, є сенс деактивувати деякі з її супутніх компонентів? Так, якщо зайти в розділ системних служб та їх компонентів (services.msc), в ньому можна знайти так званий локатор RPC.

А ось його можна деактивувати, не побоюючись за появу катастрофічних наслідків. Увійшовши у редагування його параметрів, потрібно зупинити роботу компонента та виставити тип запуску на вимкнений. Програми, які можуть використовувати віддалені процедури, виклик віддалених процедур здійснять і так (без допомоги).

Якщо з якихось причин встановлені параметри не спрацюють, можна скористатися інсталяційним диском Windows, завантажуючи з нього викликати командний рядок і вписати наступне:

  • cd X:\i386 (X - буква знімного диска);
  • expand explorer.ex_%TEMP%\explorer.exe;
  • expand svchost.ex_%TEMP%\svchost.exe.

Після перезавантаження викликається «Диспетчер задач», і в ньому завершується потім у командному рядку прописується поєднання copy %TEMP%\explorer.exe %SYSTEMROOT% /y, після чого в «Диспетчері задач» завершуються абсолютно всі процеси svchost. Тепер слід бути особливо уважним, оскільки після завершення процесів протягом лише шістдесяти секунд у командній консолі потрібно встигнути прописати команду copy %TEMP%\svchost.exe %systemroot%\system32 /y.

Якщо у користувача, наприклад, у звичайному або в безпечному режимі є доступ до системного реєстру, у редакторі (regedit) у гілці HKCC необхідно знайти параметр CSConfigFlags і надати йому значення у вигляді нуля.

Усунення збою 1726

Нарешті, усунення помилки 1726 року також проводиться через реєстр. Але в даному випадку у гілці HKLM потрібно знайти каталог RpcSs, а праворуч відредагувати значення параметра Start.

Його необхідно замінити з четвірки, зазвичай встановлюваної за замовчуванням, на двійку, після чого зробити рестарт системи.

Післямова

Ось, власне, і все щодо виклику віддалених процедур. Видалені процедури, принципи роботи цього компонента в розширеному варіанті можна описувати ще дуже довго, але наголос у представленому матеріалі був зроблений на загальному ознайомленні зі службою та деяких методах усунення помилок та збоїв, які вона може викликати у комп'ютерній системі. Пересічним користувачам доведеться запастися терпінням і бути дуже уважними, оскільки одна неправильна дія в реєстрі може призвести до повного фарбування операційної системи.

Зверніть увагу, що збої такого типу жодними іншими засобами на зразок програм-оптимізаторів та налаштувачів параметрів операційних систем Windows не усуваються. При всьому бажанні ні командний рядок, ні тим більше втручання в реєстр на рівні редагування ключів у таких програмних пакетах не передбачено.

Лекція 4

4.1 Концепція віддаленого виклику процедур

Ідея виклику віддалених процедур (Remote Procedure Call - RPC)полягає у розширенні добре відомого та зрозумілого механізму передачі управління та даних усередині програми, що виконується на одній машині, на передачу управління та даних через мережу. Засоби дистанційного виклику процедур призначені для полегшення організації розподілених обчислень. Найбільша ефективність використання RPC досягається в тих додатках, в яких існує інтерактивний зв'язок між віддаленими компонентами з невеликим часом відповідей і відносно малою кількістю даних, що передаються. Такі програми називаються RPC-орієнтованими.

Характерними рисами виклику локальних процедур є: асиметричність, тобто одна із сторін, що взаємодіють, є ініціатором; синхронність, тобто виконання зухвалої процедури при зупиняється з моменту видачі запиту і відновлюється тільки після повернення з процедури, що викликається.

Реалізація віддалених дзвінків суттєво складніша за реалізацію дзвінків локальних процедур. Почнемо з того, що оскільки процедура, що викликає і викликається, виконуються на різних машинах, то вони мають різні адресні простори, і це створює проблеми при передачі параметрів і результатів, особливо якщо машини не ідентичні. Так як RPC не може розраховувати на пам'ять, що розділяється, це означає, що параметри RPC не повинні містити покажчиків на комірки нестекової пам'яті і що значення параметрів повинні копіюватися з одного комп'ютера на інший. Наступною відмінністю RPC від локального виклику є те, що він обов'язково використовує систему зв'язку, проте це не повинно бути явно видно ні у визначенні процедур, ні в самих процедурах. Відстань вносить додаткові проблеми. Виконання програми, що викликає, і локальної процедури, що викликається, в одній машині реалізується в рамках єдиного процесу. Але в реалізації RPC беруть участь як мінімум два процеси - по одному в кожній машині. У випадку, якщо один з них аварійно завершиться, можуть виникнути такі ситуації: при аварії викликаної процедури віддалено викликані процедури стануть "осиротілими", а при аварійному завершенні віддалених процедур стануть "знедоленими батьками" процедури, що викликають безрезультатно, які безрезультатно чекатимуть відповіді від віддалених процедур.

Крім того, існує ряд проблем, пов'язаних з неоднорідністю мов програмування та операційних середовищ: структури даних і структури виклику процедур, що підтримуються в одній мові програмування, не підтримуються так само у всіх інших мовах.


Ці та деякі інші проблеми вирішує поширена технологія RPC, що лежить в основі багатьох розподілених операційних систем.

Базові операції RPC

Щоб зрозуміти роботу RPC, розглянемо спочатку виконання виклику локальної процедури у звичайній машині, що працює автономно. Нехай це, наприклад, буде системний виклик

count = read (fd, buf, nbytes);

де fd - ціле число;

buf – масив символів;

nbytes – ціле число.

Щоб здійснити виклик, процедура, що викликає, заштовхує параметри в стек у зворотному порядку. Після того, як виклик read виконаний, він поміщає значення, що повертається в регістр, переміщує адресу повернення і повертає управління викликає процедурі, яка вибирає параметри з стека, повертаючи його у вихідний стан. Зауважимо, що у мові З параметри можуть викликатися або за посиланням (by name), або за значенням (by value). По відношенню до викликаної процедури параметри-значення є локальними змінними, що ініціалізуються. Процедура, що викликається, може змінити їх, і це не вплине на значення оригіналів цих змінних у зухвалій процедурі.

Якщо процедуру, що викликається, передається покажчик на змінну, то зміна значення цієї змінної викликаної процедурою тягне зміну значення цієї змінної і для процедури, що викликає. Цей факт дуже суттєвий для RPC.

Існує також інший механізм передачі параметрів, який не використовується в мові С. Він називається call-by-copy/restore і полягає в необхідності копіювання програмою, що викликає, змінних у стек у вигляді значень, а потім копіювання назад після виконання виклику поверх оригінальних значень викликаючої процедури.

Рішення про те, який механізм передачі параметрів використовувати, приймається розробниками мови. Іноді це залежить від типу даних, що передаються. У мові З, наприклад, цілі та інші скалярні дані завжди передаються за значенням, а масиви – за посиланням.

Ідея, покладена в основу RPC, полягає в тому, щоб зробити виклик віддаленої процедури таким, що виглядає по можливості так само, як і виклик локальної процедури. Іншими словами - зробити RPC прозорим: викликає процедурі не потрібно знати, що процедура знаходиться на іншій машині, і навпаки.

RPC досягає прозорості наступним шляхом. Коли викликана процедура є віддаленою, в бібліотеку поміщається замість локальної процедури інша версія процедури, звана клієнтським стабом (stub - заглушка). Подібно до оригінальної процедури, стаб викликається з використанням послідовності, що викликає, так само відбувається переривання при зверненні до ядра. Тільки на відміну від оригінальної процедури він не поміщає параметри в регістри і не просить у ядра дані, натомість він формує повідомлення для відправлення ядру віддаленої машини.

Етапи виконання RPC

Взаємодія програмних компонентів під час виконання віддаленого виклику процедури ілюструється малюнком 2.

Рисунок 2. Remote Procedure Call

Після того, як клієнтський стаб був викликаний програмою-клієнтом, його першим завданням є заповнення буфера повідомленням. У деяких системах клієнтський стаб має єдиний буфер фіксованої довжини, що заповнюється щоразу від початку при надходженні кожного нового запиту. В інших системах буфер повідомлення є пул буферів для окремих полів повідомлення, причому деякі з цих буферів вже заповнені. Цей метод особливо підходить для випадків, коли пакет має формат, що складається з великої кількості полів, але значення багатьох з цих полів не змінюються від виклику до виклику.

Потім параметри повинні бути перетворені на відповідний формат і вставлені в буфер повідомлення. До цього моменту повідомлення готове до передачі, тому виконується переривання на виклик ядра.

Коли ядро ​​отримує керування, воно перемикає контексти, зберігає регістри процесора та картку пам'яті (дескриптори сторінок), встановлює нову картку пам'яті, яка використовуватиметься для роботи в режимі ядра. Оскільки контексти ядра та користувача різняться, ядро ​​має точно скопіювати повідомлення у свій власний адресний простір, так, щоб мати до нього доступ, запам'ятати адресу призначення (а, можливо, інші поля заголовка), а також воно має передати його мережному інтерфейсу. На цьому завершується робота на стороні клієнта. Включається таймер передачі, і ядро ​​може виконувати циклічне опитування наявності відповіді, або передати управління планувальнику, який вибере будь-який інший процес на виконання. У першому випадку прискорюється виконання запиту, але мультипрограмування відсутнє.

На стороні сервера біти, що надходять, поміщаються приймаючою апаратурою або у вбудований буфер, або в оперативну пам'ять. Коли всю інформацію буде отримано, генерується переривання. Обробник переривання перевіряє правильність даних пакета та визначає, якому стабу слід їх передати. Якщо жоден зі стабів не чекає на цей пакет, обробник повинен або помістити його в буфер, або взагалі відмовитися від нього. Якщо є очікуваний стаб, повідомлення копіюється йому. Нарешті, виконується перемикання контекстів, у результаті відновлюються регістри і картка пам'яті, приймаючи ті значення, що вони мали у момент, коли стаб зробив виклик receive.

Тепер розпочинає роботу серверний стаб. Він розпаковує параметри та поміщає їх відповідним чином у стек. Коли все готово, виконується виклик сервера. Після виконання процедури, сервер передає результати клієнту. Для цього виконуються всі описані вище етапи лише у зворотному порядку.

Рисунок 3 показує послідовність команд, які потрібно виконати для кожного RPC-дзвінка.

Рисунок 3. Етапи виконання процедури RPC

Ідея виклику віддалених процедур (Remote Procedure Call - RPC)полягає у розширенні добре відомого та зрозумілого механізму передачі управління та даних усередині програми, що виконується на одній машині, на передачу управління та даних через мережу. Засоби дистанційного виклику процедур призначені для полегшення організації розподілених обчислень.

Найбільша ефективність використання RPC досягається в додатках, в яких існує інтерактивний зв'язок між віддаленими компонентамиз невеликим часом відповідейі відносно малою кількістю даних, що передаються.Такі програми називаються RPC-орієнтованими.

Характерними рисами виклику локальних процедур є:

    Асиметричність,тобто одна із взаємодіючих сторін є ініціатором;

    Синхронність,тобто виконання зухвалої процедури зупиняється з моменту видачі запиту і відновлюється тільки після повернення з процедури, що викликається.

Реалізація віддалених дзвінків суттєво складніша за реалізацію дзвінків локальних процедур.

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

Так як RPC не може розраховувати на пам'ять, що розділяється, то це означає, що параметри RPC не повинні містити покажчиків на комірки нестікової пам'ятіі що значення параметрів повинні копіюватися з одного комп'ютера на інший.

2. Наступною відмінністю RPC від локального виклику є те, що він обов'язково використовує нижчу систему зв'язку, проте це не повинно бути явно видно ні у визначенні процедур, ні в самих процедурах .

Відстань вносить додаткові проблеми. Виконання програми, що викликає, і локальної процедури, що викликається, в одній машині реалізується в рамкахєдиного процесу. Але у реалізації RPC беруть участьяк мінімум два процеси - по одному в кожній машині. У випадку, якщо один із них аварійно завершиться, можуть виникнути такі ситуації:

    при аварії викликає процедури віддалено викликані процедури стануть "осиротілими", а

    при аварійному завершенні віддалених процедур стануть "знедоленими батьками" викликаючі процедури, які безрезультатно чекатимуть на відповідь від віддалених процедур.

Крім того, існує ряд проблем, пов'язаних з неоднорідністю мов програмування та операційних середовищ : структури даних і структури виклику процедур, що підтримуються в одній мові програмування, не підтримуються так само у всіх інших мовах.

Ці та деякі інші проблеми вирішує поширена технологія RPC, що лежить в основі багатьох розподілених операційних систем.

Ідея, покладена в основу RPC, полягає в тому, щоб зробити виклик віддаленої процедури таким, що виглядає по можливості так само, як і виклик локальної процедури. Іншими словами - зробити RPC прозорим: викликає процедурі не потрібно знати, що процедура знаходиться на іншій машині, і навпаки.

RPC досягає прозорості наступним шляхом. Коли викликана процедура є віддаленою, в бібліотеку поміщається замість локальної процедури інша версія процедури, звана клієнтським стабом (stub - заглушка). Подібно до оригінальної процедури, стаб викликається з використанням зухвалої послідовності (як на малюнку 3.1), так само відбувається переривання при зверненні до ядра. Тільки на відміну від оригінальної процедури він не поміщає параметри в регістри і не просить у ядра дані, натомість він формує повідомлення для відправки ядру віддаленої машини.

Рис. 3.2. Remote Procedure Call

Виклик віддалених процедур (RPC) Концепція віддаленого виклику процедур

Ідея виклику віддалених процедур (Remote Procedure Call - RPC) полягає у розширенні добре відомого та зрозумілого механізму передачі управління та даних усередині програми, що виконується на одній машині, на передачу управління та даних через мережу. Засоби дистанційного виклику процедур призначені для полегшення організації розподілених обчислень. Найбільша ефективність використання RPC досягається в тих додатках, в яких існує інтерактивний зв'язок між віддаленими компонентами з невеликим часом відповідей і відносно малою кількістю даних, що передаються. Такі програми називаються RPC-орієнтованими.

Характерними рисами виклику локальних процедур є:

Асиметричність, тобто одна із сторін, що взаємодіють, є ініціатором; Синхронність, тобто виконання зухвалої процедури при зупиняється з моменту видачі запиту і відновлюється тільки після повернення з процедури, що викликається.

Реалізація віддалених дзвінків суттєво складніша за реалізацію дзвінків локальних процедур. Почнемо з того, що оскільки процедура, що викликає і викликається, виконуються на різних машинах, то вони мають різні адресні простори, і це створює проблеми при передачі параметрів і результатів, особливо якщо машини не ідентичні. Так як RPC не може розраховувати на пам'ять, що розділяється, це означає, що параметри RPC не повинні містити покажчиків на комірки нестекової пам'яті і що значення параметрів повинні копіюватися з одного комп'ютера на інший. Наступною відмінністю RPC від локального виклику є те, що він обов'язково використовує систему зв'язку, проте це не повинно бути явно видно ні у визначенні процедур, ні в самих процедурах. Відстань вносить додаткові проблеми. Виконання програми, що викликає, і локальної процедури, що викликається, в одній машині реалізується в рамках єдиного процесу. Але в реалізації RPC беруть участь як мінімум два процеси - по одному в кожній машині. У випадку, якщо один з них аварійно завершиться, можуть виникнути такі ситуації: при аварії викликаної процедури віддалено викликані процедури стануть "осиротілими", а при аварійному завершенні віддалених процедур стануть "знедоленими батьками" процедури, що викликають безрезультатно, які безрезультатно чекатимуть відповіді від віддалених процедур.

Крім того, існує ряд проблем, пов'язаних з неоднорідністю мов програмування та операційних середовищ: структури даних і структури виклику процедур, що підтримуються в одній мові програмування, не підтримуються так само у всіх інших мовах.

Ці та деякі інші проблеми вирішує поширена технологія RPC, що лежить в основі багатьох розподілених операційних систем.

Базові операції RPC

Щоб зрозуміти роботу RPC, розглянемо спочатку виконання виклику локальної процедури у звичайній машині, що працює автономно. Нехай це, наприклад, буде системний виклик

Count = read (fd, buf, nbytes);

де fd - ціле число,
buf - масив символів,
nbytes – ціле число.

Щоб здійснити виклик, процедура, що викликає, заштовхує параметри в стек у зворотному порядку (рисунок 3.1). Після того, як виклик read виконаний, він поміщає значення, що повертається в регістр, переміщує адресу повернення і повертає управління викликає процедурі, яка вибирає параметри з стека, повертаючи його у вихідний стан. Зауважимо, що у мові З параметри можуть викликатися або за посиланням (by name), або за значенням (by value). По відношенню до викликаної процедури параметри-значення є локальними змінними, що ініціалізуються. Процедура, що викликається, може змінити їх, і це не вплине на значення оригіналів цих змінних у зухвалій процедурі.

Якщо процедуру, що викликається, передається покажчик на змінну, то зміна значення цієї змінної викликаної процедурою тягне зміну значення цієї змінної і для процедури, що викликає. Цей факт дуже суттєвий для RPC.

Існує також інший механізм передачі параметрів, який не використовується в мові С. Він називається call-by-copy/restore і полягає в необхідності копіювання програмою, що викликає, змінних у стек у вигляді значень, а потім копіювання назад після виконання виклику поверх оригінальних значень викликаючої процедури.

Рішення про те, який механізм передачі параметрів використовувати, приймається розробниками мови. Іноді це залежить від типу даних, що передаються. У мові З, наприклад, цілі та інші скалярні дані завжди передаються за значенням, а масиви – за посиланням.

Рис. 3.1. а) Стек до виконання дзвінка read;
б) стек під час виконання процедури;
в) Стек після повернення у викликаючу програму

Ідея, покладена в основу RPC, полягає в тому, щоб зробити виклик віддаленої процедури таким, що виглядає по можливості так само, як і виклик локальної процедури. Іншими словами - зробити RPC прозорим: викликає процедурі не потрібно знати, що процедура знаходиться на іншій машині, і навпаки.

RPC досягає прозорості наступним шляхом. Коли викликана процедура є віддаленою, в бібліотеку поміщається замість локальної процедури інша версія процедури, звана клієнтським стабом (stub - заглушка). Подібно до оригінальної процедури, стаб викликається з використанням зухвалої послідовності (як на малюнку 3.1), так само відбувається переривання при зверненні до ядра. Тільки на відміну від оригінальної процедури він не поміщає параметри в регістри і не просить у ядра дані, натомість він формує повідомлення для відправлення ядру віддаленої машини.

Етапи виконання RPC

Взаємодія програмних компонентів під час виконання віддаленого виклику процедури ілюструється малюнком 3.2. Після того, як клієнтський стаб був викликаний програмою-клієнтом, його першим завданням є заповнення буфера повідомленням. У деяких системах клієнтський стаб має єдиний буфер фіксованої довжини, що заповнюється щоразу від початку при надходженні кожного нового запиту. В інших системах буфер повідомлення є пул буферів для окремих полів повідомлення, причому деякі з цих буферів вже заповнені. Цей метод особливо підходить для випадків, коли пакет має формат, що складається з великої кількості полів, але значення багатьох з цих полів не змінюються від виклику до виклику.

Потім параметри повинні бути перетворені на відповідний формат і вставлені в буфер повідомлення. До цього моменту повідомлення готове до передачі, тому виконується переривання на виклик ядра.

Рис. 3.2. Remote Procedure Call

Коли ядро ​​отримує керування, воно перемикає контексти, зберігає регістри процесора та картку пам'яті (дескриптори сторінок), встановлює нову картку пам'яті, яка використовуватиметься для роботи в режимі ядра. Оскільки контексти ядра та користувача різняться, ядро ​​має точно скопіювати повідомлення у свій власний адресний простір, так, щоб мати до нього доступ, запам'ятати адресу призначення (а, можливо, інші поля заголовка), а також воно має передати його мережному інтерфейсу. На цьому завершується робота на стороні клієнта. Включається таймер передачі, і ядро ​​може виконувати циклічне опитування наявності відповіді, або передати управління планувальнику, який вибере будь-який інший процес на виконання. У першому випадку прискорюється виконання запиту, але мультипрограмування відсутнє.

На стороні сервера біти, що надходять, поміщаються приймаючою апаратурою або у вбудований буфер, або в оперативну пам'ять. Коли всю інформацію буде отримано, генерується переривання. Обробник переривання перевіряє правильність даних пакета та визначає, якому стабу слід їх передати. Якщо жоден зі стабів не чекає на цей пакет, обробник повинен або помістити його в буфер, або взагалі відмовитися від нього. Якщо є очікуваний стаб, повідомлення копіюється йому. Нарешті, виконується перемикання контекстів, у результаті відновлюються регістри і картка пам'яті, приймаючи ті значення, що вони мали у момент, коли стаб зробив виклик receive.

Тепер розпочинає роботу серверний стаб. Він розпаковує параметри та поміщає їх відповідним чином у стек. Коли все готово, виконується виклик сервера. Після виконання процедури, сервер передає результати клієнту. Для цього виконуються всі описані вище етапи лише у зворотному порядку.

Рисунок 3.3 показує послідовність команд, яку необхідно виконати для кожного RPC-виклику, а малюнок 3.4 - яка частка загального часу виконання RPC витрачається на виконання кожного з описаних 14 етапів. Дослідження були проведені на мультипроцесорній робочій станції DEC Firefly, і хоча наявність п'яти процесорів обов'язково вплинула на результати вимірювань, наведена на малюнку гістограма дає загальне уявлення про процес виконання RPC.

Рис. 3.3. Етапи виконання процедури RPC

Рис. 3.4. Розподіл часу між 14 етапами виконання RPC

1. Виклик стаба

2. Підготувати буфер

3. Упакувати параметри

4. Заповнити поле заголовка

5. Обчислити контрольну суму у повідомленні

6. Переривання до ядра

7. Черга пакету виконання

8. Надсилання повідомлення контролеру по шині QBUS

9. Час передачі через мережу Ethernet

10. Отримати пакет від контролера

11. Процедура обробки переривання

12. Обчислення контрольної суми

13. Переключення контексту на простір користувача

14. Виконання серверного стаба

Динамічне зв'язування

Розглянемо питання, як клієнт задає місце розташування сервера. Одним із методів вирішення цієї проблеми є безпосереднє використання мережевої адреси сервера у клієнтській програмі. Недолік такого підходу - його надзвичайна негнучкість: при переміщенні сервера, або при збільшенні числа серверів, або при зміні інтерфейсу у всіх цих та інших випадках необхідно перекомпілювати всі програми, які використовували жорстке завдання адреси сервера. Щоб уникнути всіх цих проблем, у деяких розподілених системах використовується так зване динамічне зв'язування.

Початковим моментом динамічного зв'язування є формальне визначення (специфікація) сервера. Специфікація містить ім'я файл-сервера, номер версії та список процедур-послуг, що надаються цим сервером для клієнтів (рис. 3.5). Для кожної процедури дається опис її параметрів із зазначенням того, чи цей параметр є вхідним або вихідним щодо сервера. Деякі параметри можуть бути одночасно вхідними та вихідними – наприклад, деякий масив, який посилається клієнтом на сервер, модифікується там, а потім повертається назад клієнту (операція copy/restore).

Рис. 3.5. Специфікація сервера RPC

Формальна специфікація сервера використовується як вихідні дані для програми-генератора стабів, яка створює як клієнтські, так і серверні стаби. Потім вони розміщуються у відповідні бібліотеки. Коли програма користувача (клієнтська) викликає будь-яку процедуру, визначену в специфікації сервера, відповідна стаб-процедура пов'язується з двійковим кодом програми. Аналогічно, коли компілюється сервер, із ним зв'язуються серверні стаби.

При запуску сервера найпершою його дією є передача свого серверного інтерфейсу спеціальної програми, званої binder"ом. Цей процес, відомий як процес реєстрації сервера, включає передачу сервером свого імені, номера версії, унікального ідентифікатора та описника місцезнаходження сервера. Описувач системно незалежний і може являти собою IP, Ethernet, X.500 або будь-яку адресу, крім того, він може містити й іншу інформацію, наприклад, що стосується аутентифікації.

Коли клієнт викликає одну з віддалених процедур вперше, наприклад, read, клієнтський стаб бачить, що він ще не приєднаний до сервера, і посилає повідомлення binder-програмі з проханням імпорту інтерфейсу потрібної версії потрібного сервера. Якщо такий сервер існує, то binder передає описник та унікальний ідентифікатор клієнтського стаба.

Клієнтський стаб при посиланні повідомлення із запитом використовує як адресу описувач. У повідомленні містяться параметри і унікальний ідентифікатор, який ядро ​​сервера використовує для того, щоб направити повідомлення, що надійшло в потрібний сервер у випадку, якщо їх кілька на цій машині.

Цей метод, що полягає в імпорті/експорті інтерфейсів, має високу гнучкість. Наприклад, може бути кілька серверів, що підтримують той самий інтерфейс, і клієнти розподіляються по серверах випадковим чином. В рамках цього методу стає можливим періодичне опитування серверів, аналіз їх працездатності та, у разі відмови, автоматичне відключення, що підвищує загальну відмовостійкість системи. Цей метод також може підтримувати автентифікацію клієнта. Наприклад, сервер може визначити, що може бути використаний лише клієнтами з певного списку.

Однак динамічне зв'язування має недоліки, наприклад, додаткові накладні витрати (тимчасові витрати) на експорт та імпорт інтерфейсів. Величина цих витрат може бути значною, оскільки багато клієнтських процесів існують короткий час, а при кожному старті процесу процедура імпорту інтерфейсу має бути знову виконана. Крім того, у великих розподілених системах може стати вузьким місцем програма binder, а створення кількох програм аналогічного призначення також збільшує накладні витрати на створення та синхронізацію процесів.

Семантика RPC у разі відмов

В ідеалі RPC має функціонувати правильно та у разі відмов. Розглянемо такі класи відмов:

Клієнт не може визначити місцезнаходження сервера, наприклад, у разі відмови потрібного сервера або через те, що програма клієнта була скомпільована давно і використовувала стару версію інтерфейсу сервера. І тут у відповідь запит клієнта надходить повідомлення, що містить код помилки. Втрачено запит від клієнта до сервера. Найпростіше рішення – через певний час повторити запит. Втрачено повідомлення у відповідь від сервера клієнту. Цей варіант складніший за попередній, оскільки деякі процедури не є ідемпотентними. Ідемпотентною називається процедура, запит виконання якої можна повторити кілька разів, і результат у своїй не зміниться. Прикладом такої процедури може бути читання файлу. Але процедура зняття деякої суми з банківського рахунку не є ідемпотентною, і в разі втрати відповіді повторний запит може істотно змінити стан рахунку клієнта. Одним із можливих рішень є приведення всіх процедур до ідемпотентного виду. Однак на практиці це не завжди вдається, тому може бути використаний інший метод – послідовна нумерація всіх запитів клієнтським ядром. Ядро сервера запам'ятовує номер найостаннішого запиту від кожного з клієнтів, і при отриманні кожного запиту виконує аналіз - чи є запит первинним або повторним. Сервер зазнав аварії після отримання запиту. Тут також важлива властивість ідемпотентності, але на жаль не може бути застосований підхід із нумерацією запитів. В даному випадку має значення, коли відбулася відмова - до або після виконання операції. Але клієнтське ядро ​​не може розпізнати ці ситуації, йому відомо тільки те, що час відповіді минув. Існує три підходи до цієї проблеми: Чекати, поки сервер не перезавантажиться і намагатися виконати операцію знову. Цей підхід гарантує, що RPC був виконаний до кінця щонайменше один раз, а можливо і більше. Відразу повідомити програму про помилку. Цей підхід гарантує, що RPC було виконано трохи більше одного разу. Третій підхід нічого не гарантує. Коли сервер відмовляє, клієнту не надається жодної підтримки. RPC може бути або виконаний взагалі, або виконаний багато разів. У всякому разі, цей спосіб дуже легко реалізувати.

Жоден із цих підходів не є дуже привабливим. А ідеальний варіант, який би гарантував одне виконання RPC, в загальному випадку не може бути реалізований з принципових міркувань. Нехай, наприклад, віддаленою операцією є друк деякого тексту, яка включає завантаження буфера принтера та встановлення одного біта в деякому регістрі керуючого принтера, в результаті якої принтер стартує. Аварія сервера може статися як за мікросекунду до, так і мікросекунду після установки керуючого біта. Момент збою цілком визначає процедуру відновлення, але клієнт про момент збою дізнатися не може. Коротше кажучи, можливість аварії сервера радикально змінює природу RPC та чітко відображає різницю між централізованою та розподіленою системою. У першому випадку крах сервера веде до краху клієнта і відновлення неможливо. У другому випадку дії відновлення системи виконати і можливо, і необхідно.

Клієнт зазнав аварії після надсилання запиту. У цьому випадку виконуються обчислення результатів, на які ніхто не очікує. Такі обчислення називають "сиротами". Наявність сиріт може викликати різні проблеми: непродуктивні витрати процесорного часу, блокування ресурсів, підміна відповіді на поточний запит на запит, який був виданий клієнтською машиною ще до перезапуску системи.

Як чинити з сиротами? Розглянемо 4 можливі рішення.

Знищення. До того, як клієнтський стаб надсилає RPC-повідомлення, він робить позначку в журналі, сповіщаючи про те, що він зараз робитиме. Журнал зберігається на диску або іншій пам'яті, стійкій до збоїв. Після аварії система перезавантажується, журнал аналізується та сироти ліквідуються. До недоліків такого підходу відносяться, по-перше, підвищені витрати, пов'язані із записом про кожен RPC на диск, а, по-друге, можлива неефективність через появу сиріт другого покоління, породжених RPC-викликами, виданими сиротами першого покоління. Перетворення. У цьому випадку всі проблеми вирішуються без запису на диск. Метод полягає у розподілі часу на послідовно пронумеровані періоди. Коли клієнт перезавантажується, він передає широкомовне повідомлення всім машинам початку нового періоду. Після отримання цього повідомлення всі видалені обчислення ліквідуються. Звичайно, якщо мережа сегментована, деякі сироти можуть і вціліти. М'яке перетворення аналогічно попередньому випадку, крім того, що перебувають і знищуються в повному обсязі видалені обчислення, лише обчислення перезагружающегося клієнта. Витікання терміну. Кожному запиту відводиться стандартний відрізок часу Т, протягом якого він має бути виконаний. Якщо запит не виконується за відведений час, виділяється додатковий квант. Хоча це і вимагає додаткової роботи, але якщо після аварії клієнта сервер чекає протягом інтервалу Т до перезавантаження клієнта, то всі сироти обов'язково знищуються.

Насправді жоден із цих підходів не бажаний, більше, знищення сиріт може посилити ситуацію. Наприклад, нехай сирота заблокувала один або більше файлів бази даних. Якщо сирота буде раптом знищено, то ці блокування залишаться, крім того, знищені сироти можуть залишитися стояти в різних системних чергах, у майбутньому вони можуть викликати виконання нових процесів і т.п.