Вызов удаленных процедур (RPC). Механизм вызова удаленных процедур - RPC Механизм работы RPC

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

Удаленный вызов процедур: что это?

Начать стоит с некоторых теоретических сведений. Как считается, удаленные процедуры (вызов удаленных процедур) - это механизм, позволяющий запускать или использовать какие-либо функции компьютерных систем в отличном от используемого терминала адресном пространстве. Проще говоря, это способ доступа к удаленному компьютеру, например, через локальную сеть или интернет-подключение.

Однако удаленные процедуры (вызов удаленных процедур), обозначаемые как RPC (сокращение от английского Remote Procedure Call), можно отнести не только к удаленным компьютерам. На локальном уровне такие технологии тоже применяются. В качестве простейшего примера можно привести вызов определенной функции одной программы из другого приложения посредством взаимодействия через специальные библиотеки.

Кроме того, абсолютно во всех версиях Windows имеется такая служба, а при ее отключении или отказе работоспособности модификация XP не работает вообще.

Принцип действия

Как правило, служба «Удаленный вызов процедур RPC» для работы в режиме клиент-сервер требует наличия как минимум двух основных компонентов: сетевого протокола для обмена данными и языка сериализации (перевода какого-то процесса или информационной структуры данных в битовую последовательность).

Архитектуры могут быть совершенно разными и отличающимися по своим возможностям. Но для обмена данными на так называемом транспортном уровне чаще всего применяются протоколы UDP и TCP, реже - HTTP.

Чтобы не вдаваться в технические аспекты, самым простым объяснением принципа работы таких технологий может стать следующие пример: клиентский процесс формирует запрос серверу с описанием выбранной процедуры с указанными параметрами и отправляет его, после чего сервер выполняет требуемую директиву и отправляет клиенту ответ, который отображается на клиентской машине. Однако сам серверный обработчик находится, так сказать, в режиме ожидания и активируется только в моменты получения клиентских запросов. При этом совсем не обязательно, чтобы выполнение схемы «запрос-ответ» производилось немедленно.

При этом максимальный эффект производительности достигается при обмене относительно малыми объемами данных и небольшим временем отклика компонентов, между которыми установлена интерактивная связь.

Удаленные процедуры (вызов удаленных процедур): характерные черты и реализации

Таким образом, можно выделить две главные особенности названных технологий:

  • асимметричность (инициация выполнения удаленной процедуры только одной из сторон);
  • синхронность (приостановка вызывающей процедуры с момента инициации запроса и возобновление после отправки ответа).

Что же касается реализаций, удаленные процедуры (вызов удаленных процедур) сегодня используют несколько базовых технологий, среди которых наиболее широко применяются следующие:

  • DCE/RPC - бинарный протокол на основе TCP/IP, SMB/SIFC и т. д.;
  • DCOM - объектно-ориентированное дополнение с возможностью передачи ссылок на объекты и вызовом методов их обработки;
  • JSON-RPC - текстовый протокол, основанный на HTTP;
  • .NET Remoting - бинарный протокол на основе UDP, TCP и HTTP;
  • JAVA RMI;
  • SOAP;
  • XML RPC;
  • SUN RPC;
  • ZeroC ICE;
  • Routix.RPC и др.

Проблемы и задачи

Теперь несколько слов о недостатках. Самая главная проблема, а соответственно, и задача реализации, состоит в том, что одна и та же операция вызова удаленной процедуры через узел службы «Удаленный вызов процедур» должна одновременно выполняться на разных машинах, причем зачастую с различными операционными системами, адресными пространствами и архитектурой. В процессе данные параметров должны копироваться с одного терминала на другой. Для этого используется не только транспортный протокол, но и сериализация, позволяющая преобразовать в байтовую последовательность разные типы данных.

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

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

Основные типы подсистем

Удаленный вызов процедур Windows 10 или любой другой системы рангом ниже подразумевает использование специальных подсистем:

  • транспортная подсистема, предназначенная для управления исходящими и входящими подключениями с гарантированной доставкой пакетов данных;
  • пул-протоколов - концепция выполнения процедуры на вызываемом терминале;
  • сериализация (маршалинг) - преобразование потоков данных в стандартные байтовые коды, независящие от архитектуры;
  • шифрование отправляемых и принимаемых пакетов с наложением на них цифровой подписи;
  • система аутентификации и авторизации.

Какие типы программ требуют выполнения RPC?

Если же говорить о том, какие программные модули операционных систем требуют держать службу RPC включенной, все их перечислить просто невозможно.

Но среди всем известных компонентов Windows-систем можно отметить службу факсов, службы криптографии, регистрацию ошибок, справку и поддержку, доступ к устройствам HID, службу сообщений (Messenger), администрирование дисков и логических разделов, управление съемными накопителями, аудиосистему, установщик Windows и еще бог весть что.

Думается, этого списка достаточно, чтобы понять, насколько многие компоненты системы, да и сам пользователь, зависимы от этой службы.

На что влияет RPC

Вообще, исходя из предыдущего описания, можно оценить влияние RPC. Так, например, известно немало случаев, когда при отключении этой службы полностью пропадал звук, невозможным оказывалось восстановление системы после критических сбоев или инициированное пользователем, «слетали» настройки беспроводной сети.

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

Можно ли отключить эту службу

По большому счету, многие пытались (и пытаются) службу «Удаленный вызов процедур» отключить. Делать это категорически запрещается. В общем-то, и сама система при осуществлении такой попытки сделать этого не даст, выдав соответствующее уведомление.

Но не все знают, что в разделе службы (services.msc) есть еще такая штука, как «Локатор удаленного вызова процедур RPC». Вот его-то как раз и можно отключить безболезненно для системы. Приложения, которые могут его использовать в своей работе, самостоятельно вызовут сервис при необходимости.

Устранение сбоев и ошибок

Наконец, посмотрим, что можно сделать, если выдается ошибка при удаленном вызове процедуры. В самом простом случае можно попытаться включить службу заново (если, конечно, получится).

Для этого в соответствующем разделе, где находится искомая служба, двойным кликом вызывается меню редактирования параметров, нажимается кнопка включения, а сам тип включения устанавливается на автоматический. Если проделать такую процедуру при стандартной загрузке системы не представляется возможным, можно попытаться произвести аналогичные действия в безопасном режиме. Некоторые специалисты советуют заодно на время проведения действий на всякий случай отключить антивирусное ПО.

Если это не поможет, но под рукой имеется установочный или восстановительный диск системы, можно запустить командную консоль с правами администратора (загружаться с диска не нужно) и прописать в ней такие команды:

  • cd z:\i386 (Z - литера оптического привода) ;
  • expand explorer.ex_ %TEMP%\explorer.exe;
  • expand svchost.ex_ %TEMP%\svchost.exe.

После этого запускаем «Диспетчер задач» (Ctrl + Del + Alt или taskmgr в меню «Выполнить») и завершаем процесс Explorer.exe.

В «Диспетчере» останавливаем все процессы svhost.exe, после чего в течение 60 секунд нужно успеть в командой строке ввести строку copy %TEMP%\svchost.exe %systemroot%\system32 /y.

Наконец, если есть доступ к редактору системного реестра (regedit) восстановлен, нужно пройти по ветке HKCC через разделы SYSTEM и CurrentControlSet и добраться до параметра CSConfigFlags, изменив его значение на ноль.

Это далеко не все методы исправления ошибок, связанных с RPC. Дело в том, что, если эта служба повлекла за собой нарущения в работе других сервисов, возможно, сначала придется устранять проблемы с их работоспособностью, а только потом предпринимать какие-то действия в отношении RPC. И не всегда к вышеописанным параметрам и настройкам можно получить полный доступ. Если уж совсем ничего не получится, как это ни плачевно звучит, придется полностью переустанавливать операционную систему, хотя хочется надеяться, что до этого дело не дойдет.

Заключение

Вот кратко и все, что касается технологии и службы RPC. На самом деле все это выглядит намного сложнее, нежели было представлено в данном описании, и для полного понимания вопроса необходимо обладать хотя бы начальными знаниями. Но для того, чтобы иметь об RPC общее представление, этого пока достаточно.

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

Механизм сокетов

Механизм сокетов (sockets) впервые появился в версии 4.3 BSD UNIX (Berkeley Software Distribution UNIX - ветвь UNIX, начавшая развиваться в калифорнийском университете Беркли). Позже он превратился в одну из самых популярных систем сетевого обмена сообщениями. Сегодня этот механизм реализован во многих операционных системах, иногда его по-прежнему называют Berkeley Sockets, отдавая дань уважения его создателям, хотя существует большое количество его реализаций как для различных ОС семейства UNIX, так и для других ОС, например для ОС семейства Windows, где он носит название Windows Sockets (WinSock).

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

Независимость от нижележащих сетевых протоколов и технологий. Для этого используется понятие коммуникационный домен (communication domain). Коммуникационный домен обладает некоторым набором коммуникационных свойств, определяющих способ именования сетевых узлов и ресурсов, характеристики сетевых соединений (надежные, дейтаграммные, упорядоченные), способы синхронизации процессов и т. п. Одним из наиболее популярных доменов является домен Интернета с протоколами стека TCP/IP.

Использование абстрактной конечной точки соединения, получившей название сокет (socket - гнездо). Сокет - это точка, через которую сообщения уходят в сеть или принимаются из сети. Сетевое соединение между двумя процессами осуществляется через пару сокетов. Каждый процесс пользуется своим сокетом, при этом сокеты могут находится как на разных компьютерах, так и на одном (в этом случае сетевое межпроцессное взаимодействие сводится к локальному).

Сокет может иметь как высокоуровневое символьное имя (адрес), так и низкоуровневое, отражающее специфику адресации определенного коммуникационного домена. Например, в домене Интернета низкоуровневое имя представлено парой (IP-адрес, порт).

Для каждого коммуникационного домена могут существовать сокеты различных типов. С помощью типа сокета можно задавать определенный вид взаимодействия, имеющий смысл для домена. Так, во многих доменах существуют дейтаграммные соединения (datagram) и соединения потоковые (stream), гарантирующие надежную упорядоченную доставку.

Еще одним удобным механизмом, облегчающим взаимодействие операционных систем и приложений по сети, является механизм вызова удаленных процедур (Remote Procedure Call, RPC). Этот механизм представляет собой надстройку над системой обмена сообщениями ОС, поэтому в ряде случаев он позволяет более удобно и прозрачно организовать взаимодействие программ по сети, однако его полезность не универсальна.

Идея вызова удаленных процедур состоит в расширении хорошо известного и понятного механизма передачи управления и данных внутри программы, выполняющейся на одной машине, на передачу управления и данных через сеть. Средства удаленного вызова процедур предназначены для облегчения организации распределенных вычислений. Впервые механизм RPC реализовала компания Sun Microsystems, и он хорошо соответствует девизу «Сеть - это компьютер», взятому этой компанией на вооружение, так как приближает сетевое программирование к локальному. Наибольшая эффективность RPC достигается в тех приложениях, в которых существует интерактивная связь между удаленными компонентами с небольшим временем ответов и относительно малым количеством передаваемых данных. Такие приложения называются RPC-ориентированными.

Характерными чертами вызова локальных процедур являются:

Асимметричность - одна из взаимодействующих сторон является инициатором взаимодействия;

Синхронность - выполнение вызывающей процедуры блокируется с момента выдачи запроса и возобновляется только после возврата из вызываемой процедуры.

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

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

При аварии вызывающей процедуры удаленно вызванные процедуры становятся «осиротевшими»;

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

Кроме того, существует ряд проблем, связанных с неоднородностью языков программирования и операционных сред: структуры данных и структуры вызова процедур, поддерживаемые в каком-либо одном языке программирования, не поддерживаются точно таким же способом в других языках.

Рассмотрим, каким образом технология RPC, лежащая в основе многих распределенных операционных систем, решает эти проблемы.

Чтобы понять работу RPC, рассмотрим сначала выполнение вызова локальной процедуры в автономном компьютере. Пусть это, например, будет процедура записи данных в файл:

m.= my_write(fd,buf.length);

Здесь fd - дескриптор файла, целое число, buf - указатель на массив символов, length - длина массива, целое число.

Чтобы осуществить вызов, вызывающая процедура помещает указанные параметры в стек в обратном порядке и передает управление вызываемой процедуре my_write. Эта пользовательская процедура после некоторых манипуляций с данными символьного массива buf выполняет системный вызов write для записи данных в файл, передавая ему параметры тем же способом, то есть помещая их в стек (при реализации системного вызова они копируются в стек системы, а при возврате из него результат помещается в пользовательский стек). После того как процедура my_write выполнена, она помещает возвращаемое значение m в регистр, перемещает адрес возврата и возвращает управление вызывающей процедуре, которая выбирает параметры из стека, возвращая его в исходное состояние. Заметим, что в языке С параметры могут вызываться по ссылке (by name), представляющей собой адрес глобальной области памяти, в которой хранится параметр, или по значению (by value), в этом случае параметр копируется из исходной области памяти в локальную память процедуры, располагаемую обычно в стековом сегменте. В первом случае вызываемая процедура работает с оригинальными значениями параметров и их изменения сразу же видны вызывающей процедуре. Во втором случае вызываемая процедура работает с копиями значений параметров, и их изменения никак не влияют на значение оригиналов этих переменных в вызывающей процедуре. Эти обстоятельства весьма существенны для RPC.

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

Рисунок 69 иллюстрирует передачу параметров вызываемой процедуре: стек до выполнения вызова write (а), стек во время выполнения процедуры (б), стек после возврата в вызывающую программу (в).

Рис. 69. Передача параметров вызываемой процедуре

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

Механизм RPC достигает прозрачности следующим образом. Когда вызываемая процедура действительно является удаленной, в библиотеку процедур вместо локальной реализации оригинального кода процедуры помещается другая версия процедуры, называемая клиентским стабом (stub - заглушка). На удаленный компьютер, который выполняет роль сервера процедур, помещается оригинальный код вызываемой процедуры, а также еще один стаб, называемый серверным стабом . Назначение клиентского и серверного стабов - организовать передачу параметров вызываемой процедуры и возврат значения процедуры через сеть, при этом код оригинальной процедуры, помещенной на сервер, должен быть полностью сохранен. Стабы используют для передачи данных через сеть средства подсистемы обмена сообщениями, то есть существующие в ОС примитивы send и receive. Иногда в подсистеме обмена сообщениями выделяется программный модуль, организующий связь стабов с примитивами передачи сообщений, называемый модулем RPCRimtime.

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

Рис. 70. Выполнение удаленного вызова процедуры

Эта операция называется операцией упаковки параметров. После этого клиентский стаб обращается к примитиву send для передачи этого сообщения удаленному компьютеру, на который помещена реализация оригинальной процедуры. Получив из сети сообщение, ядро ОС удаленного компьютера вызывает серверный стаб, который извлекает из сообщения параметры и вызывает обычным образом оригинальную процедуру. Для получения сообщения серверный стаб должен предварительно вызвать примитив receive, чтобы ядро знало, для кого пришло сообщение. Серверный стаб распаковывает параметры вызова, имеющиеся в сообщении, и обычным образом вызывает оригинальную процедуру, передавая ей параметры через стек. После окончания работы процедуры серверный стаб упаковывает результат ее работы в новое сообщение и с помощью примитива send передает сообщение по сети клиентскому стабу, а тот возвращает обычным образом результат и управление вызывающей процедуре. Ни вызывающая процедура, ни оригинальная вызываемая процедура не изменились оттого, что они стали работать на разных компьютерах.

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

Автоматический способ основан на применении специального языка определения интерфейса (Interface Definition Language, IDL). С помощью этого языка программист описывает интерфейс между клиентом и сервером RPC. Описание включает список имен процедур, выполнение которых клиент может запросить у сервера, а также список типов аргументов и результатов этих процедур. Информация, содержащаяся в описании интерфейса, достаточна для выполнения стабами проверки типов аргументов и генерации вызывающей последовательности. Кроме того, описание интерфейса содержит некоторую дополнительную информацию, полезную для оптимизации взаимодействия стабов, например каждый аргумент помечается как входной, выходной или играющий и ту, и другую роли (входной аргумент передается от клиента серверу, а выходной - в обратном направлении). Интерфейс может включать также описание общих для клиента и сервера констант. Необходимо подчеркнуть, что обычно интерфейс RPC включает не одну, а некоторый набор процедур, выполняющих взаимосвязанные функции, например функции доступа к файлам, функции удаленной печати и т. п. Поэтому при вызове удаленной процедуры обычно необходимо каким-то образом задать нужный интерфейс, а также конкретную процедуру, поддерживаемую этим интерфейсом. Часто интерфейс также называют сервером RPC, например файловый сервер, сервер печати.

После того как описание интерфейса составлено программистом, оно компилируется специальным IDL-компилятором, который вырабатывает исходные модули клиентских и серверных стабов для указанных в описании процедур, а также генерирует специальные файлы-заголовки с описанием типов процедур и их аргументов. Генерации исходных модулей и файлов-заголовков стабов выполняются для конкретного языка, программирования, например для языка С. После этого исходные модули интерфейса могут включаться в любое приложение наряду с любыми другими модулями как написанными программистом, так и библиотечными, компилироваться и связываться в исполняемую программу стандартными средствами инструментальной системы программирования.

Механизм RPC оперирует двумя типами сообщений: сообщениями-вызовами, с помощью которых клиент запрашивает у сервера выполнение определенной удаленной процедуры и передает ее аргументы; сообщениями-ответами, с помощью которых сервер возвращает результат работы удаленной процедуры клиенту.

С помощью этих сообщений реализуется протокол RPC, определяющий способ взаимодействия клиента с сервером. Протокол RPC обычно не зависит от транспортных протоколов, с помощью которых сообщения RPC доставляются по сети от клиента к серверу и обратно. При использования в сети стека протоколов TCP/IP это могут быть протоколы TCP или UDP, в локальных сетях часто используется также NetBEUI/NetBIOS или IPX/SPX.

Типичный формат двух типов сообщений, используемых RPC, показан на рисунке 71.

Рис. 71. Формат сообщений RPC

Тип сообщения позволяет отличить сообщения-вызовы от сообщений-ответов. Поле идентификатора удаленной процедуры в сообщении-вызове позволяет серверу понять, вызов какой процедуры запрашивает в сообщении клиент (процедуры идентифицируются не именами, а номерами, которые при автоматической генерации стабов присваивает им IDL-компилятор, а при ручной - программист). Поле аргументов имеет переменную длину, определяемую количеством и типом аргументов вызываемой процедуры. В поле идентификатора сообщения помещается порядковый номер сообщения, который полезен для обнаружения фактов потерь сообщений или прихода дубликатов сообщений. Кроме того, этот номер позволяет клиенту правильно сопоставить полученный от сервера ответ со своим вызовом в том случае, когда ответы приходят не в том порядке, в котором посылались вызовы. Идентификатор клиента нужен серверу для того, чтобы знать, какому клиенту нужно отправить результат работы вызываемой процедуры. Это поле может также использоваться в процедурах аутентификации клиента, если эти процедуры предусмотрены протоколом RPC.

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

Для устойчивой работы серверов и клиентов RPC необходимо каким-то образом обрабатывать ситуации, связанные с потерями сообщений, которые происходят из-за ошибок сети (эти ошибки транспортные протоколы пытаются компенсировать, но все равно некоторая вероятность потерь все же остается) или же по причине краха операционной системы и перезагрузки компьютера (здесь транспортные протоколы исправить ситуацию не могут). Протокол RPC использует в таких случаях механизм тайм-аутов с повторной передачей сообщений. Для того чтобы сервер мог повторно переслать клиенту потерянный результат без необходимости передачи от клиента повторного вызова, в протокол RPC иногда добавляется специальное сообщение - подтверждение клиента, которое тот посылает при получении ответа от сервера.

Рассмотрим вопрос о том, как клиент узнает место расположения сервера, которому необходимо послать сообщение-вызов. Процедура, устанавливающая соответствие между клиентом и сервером RPC, носит название связывание (binding). Методы связывания, применяемые в различных реализациях RPC, отличаются:

Способом задания сервера, с которым хотел бы быть связанным клиент;

Способом обнаружения сетевого адреса (места расположения) требуемого сервера процессом связывания;

Стадией, на которой происходит связывание.

Метод связывания тесно связан с принятым методом именования сервера. В наиболее простом случае имя или адрес сервера RPC задается в явной форме, в качестве аргумента клиентского стаба или программы-сервера, реализующей интерфейс определенного типа. Например, можно использовать в качестве такого аргумента IP-адрес компьютера, на котором работает некоторый RPC-сервер, и номер TCP/UDP порта, через который он принимает сообщения-вызовы своих процедур. Основной недостаток такого подхода - отсутствие гибкости и прозрачности. При перемещении сервера или при существовании нескольких серверов клиентская программа не может автоматически выбрать новый сервер или тот сервер, который в данный момент наименее загружен. Тем не менее во многих случаях такой способ вполне приемлем и ввиду своей простоты часто используется на практике. Необходимый сервер часто выбирает пользователь, например, путем просмотра списка или графического представления имеющихся в сети разделяемых файловых систем (набор этих файловых систем может быть собран операционной системой клиентского компьютера за счет прослушивания широковещательных объявлений, которые периодически делают серверы). Кроме того, пользователь может задать имя требуемого сервера на основании заранее известной ему информации об адресе или имени сервера.

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

Динамическое связывание требует изменения способа именования сервера. Наиболее гибким является использование для этой цели имени RPC-интерфейса, состоящего из двух частей:

Типа интерфейса;

Экземпляра интерфейса.

Тип интерфейса определяет все характеристики интерфейса, кроме его месторасположения. Это те же характеристики, который имеются в описании для IDL-компилятора, например файловая служба определенной версии, включающая процедуры open, close, read, write, и т. п. Часть, описывающая экземпляр интерфейса, должна точно задавать сетевой адрес сервера, который поддерживает данный интерфейс. Если клиенту безразлично, какой сервер его будет обслуживать, то вторая часть имени интерфейса опускается.

Динамическое связывание иногда называют импортом/экспортом интерфейса: клиент импортирует интерфейс, а сервер его экспортирует.

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

С использованием широковещания;

С использованием централизованного агента связывания.

Эти два способа характерны для поиска сетевого ресурса любого типа по его имени, они уже рассматривались в общем виде в подразделе «Способы адресации» раздела «Механизм передачи сообщений в распределенных системах». Первый способ основан на широковещательном распространении по сети серверами RPC имени своего интерфейса, включая и адрес экземпляра. Применение этого способа позволяет автоматически балансировать нагрузку на несколько серверов, поддерживающий один и тот же интерфейс, - клиент просто выбирает первое из подходящих ему объявлений.

Схема с централизованным агентом связывания предполагает наличие в сети сервера имен, который связывает тип интерфейса с адресом сервера, поддерживающего такой интерфейс. Для реализации этой схемы каждый сервер RPC должен предварительно зарегистрировать тип своего интерфейса и сетевой адрес у агента связывания, работающего на сервере имен. Сетевой адрес агента связывания (в формате, принятом в данной сети) должен быть известным адресом как для серверов RPC, так и для клиентов. Если сервер по каким-то причинам не может больше поддерживать определенный RFC-интерфейс, то он должен обратиться к агенту и отменить свою регистрацию. Агент связывания на основании запросов регистрации ведет таблицу текущего наличия в сети серверов и поддерживаемых ими RFC-интерфейсов.

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

Агент связывания может работать в составе общей централизованной справочной службы сети, такой как NDS, X.500 или LDAP (справочные службы более подробно рассматриваются в следующей главе).

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

Однако у динамического связывания имеются недостатки, например дополнительные накладные расходы (временные затраты) на экспорт и импорт интерфейсов. Величина этих затрат может быть значительна, так как многие клиентские процессы существуют короткое время, а при каждом старте процесса процедура импорта интерфейса должна выполняться заново. Кроме того, в больших распределенных системах может стать узким местом агент связывания, и тогда необходимо использовать распределенную систему агентов, что можно сделать стандартным способом, используя распределенную справочную службу (таким свойством обладают службы NDS, X.500 и LDAP).

Необходимо отметить, что и в тех случаях, когда используется статическое связывание, такая часть адреса, как порт сервера интерфейса (то есть идентификатор процесса, обслуживающего данный интерфейс), определяется клиентом динамически. Эту процедуру поддерживает специальный модуль RPCRuntime, называемый в ОС UNIX модулем отображения портов (portmapper), а в ОС семейства Windows - локатором RFC (RPC Locator). Этот модуль работает на каждом сетевом узле, поддерживающем механизм RPC, и доступен по хорошо известному порту TCP/UDP. Каждый сервер RPC, обслуживающий определенный интерфейс, при старте обращается к такому модулю с запросом о выделении ему для работы номера порта из динамически распределяемой области (то есть с номером, большим 1023). Модуль отображения портов выделяет серверу некоторый свободный номер порта и запоминает это отображение в своей таблице, связывая порт с типом интерфейса, поддерживаемым сервером. Клиент RPC, выяснив каким-либо образом сетевой адрес узла, на котором имеется сервер RPC с нужным интерфейсом, предварительно соединяется с модулем отображения портов по хорошо известному порту и запрашивает номер порта искомого сервера. Получив ответ, клиент использует данный номер для отправки сообщений - вызовов удаленных процедур. Механизм очень похож на механизм, лежащий в основе работы агента связывания, но только область его действия ограничивается портом одного компьютера.



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

Интерфейс RPC можно представить состоящим из трех уровней:

  1. Верхний уровень полностью "прозрачен". Программа этого уровня может, например, содержать обращение к процедуре rnusers(), возвращающей число пользователей на удаленной машине. Вам не нужно знать об использовании механизма RPC, поскольку вы делаете обращение в программе.
  2. Средний уровень предназначен для наиболее общих приложений. RPC-вызовами на этом уровне занимаются подпрограммы registerrpc() и callrpc(): registerrpc() получает общесис темный код, а callrpc() исполняет вызов удаленной процедуры. Вызов rnusers() реализуется с помощью этих двух подпрограмм.
  3. Нижний уровень используется для более сложных задач, изменяющих умолчания на значения параметров процедур. На этом уровне вы можете явно манипулировать гнездами, используемыми для передачи RPC-сообщений.

Как правило, вам следует пользоваться верхним уровнем и избегать использования нижних уровней без особой необходимости.

Несмотря на то, что в данном руководстве мы рассматриваем интерфейс только на Си, обращение к удаленным процедурам может быть сделано из любого языка. Работа механизма 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 на определенный порт - III. На этот порт клиент отправляет широковещательное сообщение запроса порта определенного сервиса 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
  1. Идентификация сообщений ответа на соответствующие запросы. Ответные сообщения RPC содержат идентификатор запроса, на основании которого они были построены. Этот идентификатор можно назвать идентификатором транзакции вызова RPC. Данный механизм особенно необходим при работе в асинхронном режиме и при выполнении последовательности из нескольких RPC-вызовов.
  2. Идентификация ошибок работы протокола. Все сетевые или серверные ошибки имеют уникальные идентификаторы, по которым каждый из участников соединения может определить причину сбоя в работе.

Структуры сообщений протокола

При передаче RPC-сообщений поверх транспортного протокола, несколько RPC-сообщений могут располагаться внутри одного транспортного пакета. Для того чтобы отделять одно сообщение от другого, используется маркер записи (RM - Record Marker). Каждое RPC-сообщение "маркируется" ровно одним RM.

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

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

Структура RPC-пакета выглядит следующим образом:


Структура ответа (reply_body) может содержать либо структуру, передаваемую в случае ошибки (тогда она содержит код ошибки), либо структуру успешной обработки запроса (тогда она содержит возвращаемые данные).

Программный интерфейс высокого уровня.

Использование подпрограмм в программе - традиционный способ структурировать задачу, сделать ее более ясной. Наиболее часто используемые подпрограммы собираются в библиотеки, где могут использоваться различными программами. В данном случае речь идет о локальном (местном) вызове, т. е. и вызывающий, и вызываемый объекты работают в рамках одной программы на одном компьютере.

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

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

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

Удаленный вызов процедуры включает следующие шаги:

  1. Программа-клиент производит локальный вызов процедуры, называемой заглушкой (stub). При этом клиенту "кажется", что, вызывая заглушку, он производит собственно вызов процедуры-сервера. И действительно, клиент передает заглушке необходимые параметры, а она возвращает результат. Однако дело обстоит не совсем так, как это себе представляет клиент. Задача заглушки - принять аргументы, предназначаемые удаленной процедуре, возможно, преобразовать их в некий стандартный формат и сформировать сетевой запрос. Упаковка аргументов и создание сетевого запроса называется сборкой (marshalling).
  2. Сетевой запрос пересылается по сети на удаленную систему. Для этого в заглушке используются соответствующие вызовы, например, рассмотренные в предыдущих разделах. Заметим, что при этом могут быть использованы различные транспортные протоколы, причем не только семейства TCP/IP.
  3. На удаленном хосте все происходит в обратном порядке. Заглушка сервера ожидает запрос и при получении извлекает параметры - аргументы вызова процедуры. Извлечение (unmarshalling) может включать необходимые преобразования (например, изменения порядка расположения байтов).
  4. Заглушка выполняет вызов настоящей процедуры-сервера, которой адресован запрос клиента, передавая ей полученные по сети аргументы.
  5. После выполнения процедуры управление возвращается в заглушку сервера, передавая ей требуемые параметры. Как и заглушка клиента; заглушка сервера преобразует возвращенные процедурой значения, формируя сетевое сообщение-отклик, который передается по сети системе, от которой пришел запрос.
  6. Операционная система передает полученное сообщение заглушке клиента, которая, после необходимого преобразования, передает значения (являющиеся значениями, возвращенными удаленной процедурой) клиенту, воспринимающему это как нормальный возврат из процедуры.

Таким образом, с точки зрения клиента, он производит вызов удаленной процедуры, как он это сделал бы для локальной. То же самое можно сказать и о сервере: вызов процедуры происходит стандартным образом, некий объект (заглушка сервера) производит вызов локальной процедуры и получает возвращенные ею значения. Клиент воспринимает заглушку как вызываемую процедуру-сервер, а сервер принимает собственную заглушку за клиента.

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

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

Передача параметров-значений не вызывает особых трудностей. В этом случае заглушка клиента размещает значение параметра в сетевом запросе возможно, выполняя преобразования к стандартному виду (например, изменяя порядок следования байтов). Гораздо сложнее обстоит дело с передачей указателей, когда параметр представляет собой адрес данных, а не их значение. Передача в запросе адреса лишена смысла, так как удаленная процедура выполняется в совершенно другом адресном пространстве. Самым простым решением, применяемым в RPC, является запрет клиентам передавать параметры иначе, как по значению, хотя это, безусловно, накладывает серьезные ограничения.

Связывание (binding)

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

  1. Нахождение удаленного хоста с требуемым сервером
  2. Нахождение требуемого серверного процесса на данном хосте

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

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

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

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

Обработка особых ситуаций (exception)

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

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

Семантика вызова

Вызов локальной процедуры однозначно приводит к ее выполнению после чего управление возвращается в головную программу. Иначе дело обстоит при вызове удаленной процедуры. Невозможно установить, когда конкретно будет выполняться процедура, будет ли она выполнена вообще, а если будет, то какое число раз? Например, если запрос будет получен удаленной системой после аварийного завершения программы сервера, процедура не будет выполнена вообще. Если клиент при неполучении отклика после определенного промежутка времени (тайм-аута) повторно посылает запрос, то может создаться ситуация, когда отклик уже передается по сети, а повторный запрос вновь принимается на обработку удаленной процедурой. В этом случае процедура будет выполнена несколько раз.

Таким образом, выполнение удаленной процедуры можно характеризовать следующей семантикой:

  • Один и только один раз. Данного поведения (в некоторых случаях наиболее желательного) трудно требовать ввиду возможных аварий сервера.
  • Максимум раз. Это означает, что процедура либо вообще не была выполнена, либо была выполнена только один раз. Подобное утверждение можно сделать при получении ошибки вместо нормального отклика.
  • Хотя бы раз. Процедура наверняка была выполнена один раз, но возможно и больше. Для нормальной работы в такой ситуации удаленная процедура должна обладать свойством идемпотентности (от англ. idemponent). Этим свойством обладает процедура, многократное выполнение которой не вызывает кумулятивных изменений. Например, чтение файла идемпотентно, а добавление текста в файл - нет.

Представление данных

Когда клиент и сервер выполняются в одной системе на одном компьютере, проблем с несовместимостью данных не возникает. И для клиента и для сервера данные в двоичном виде представляются одинаково. В случае удаленного вызова дело осложняется тем, что клиент и сервер могут выполняться на системах с различной архитектурой, имеющих различное представление данных (например, представление значения с плавающей точкой, порядок следования байтов и т. д.)

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

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

  1. Порядок следования байтов - Старший - последний
  2. Представление значений с плавающей точкой - IEEE
  3. Представление символа - 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; } = 1; } = 0х31234567;

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


Рассмотрим этот файл внимательно. Компилятор транслирует имя RLOG определенное в файле описания интерфейса, в rlog_1, заменяя прописные символы на строчные и добавляя номер версии программы с подчеркиванием. Тип возвращаемого значения изменился с int на int *. Таково правило - RPC позволяет передавать и получать только адреса объявленных при описании интерфейса параметров. Это же правило касается и передаваемой в качестве аргумента строки. Хотя из файла print.h это не следует, на самом деле в качестве аргумента функции rlog_l () также передается адрес строки.

Помимо файла заголовков компилятор rpcgen(l) создает модули заглушки клиента и заглушки сервера. По существу, в тексте этих файлов заключен весь код удаленного вызова.

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


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

client.c


#include #include "log.h" main (int argc, char *argv) { CLIENT *cl; char *server, *mystring, *clnttime; time_t bintime; int *result; if (argc != 2) { fprintf(stderr, "Формат вызова: %s Адрес_хоста\n", argv ); exit (1) ; } server = argv ; /*Получим дескриптор клиента. В случае неудачи - сообщим о невозможности установления связи с сервером*/ if ((с1 = clnt_create (server, LOG_PROG, LOG_VER, "udp")) == NULL) { clnt_pcreateerror (server); exit (2); } /*Выделим буфер для строки*/ 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); exit(3); } /*B случае неудачи на удаленном компьютере сообщим об ошибке*/ if (*result !=0) fprintf(stderr, "Ошибка записи в журнал\n"); /*0свободим дескриптор*/ cint destroy(cl); exit (0); }

Заглушка клиента log_clnt.c компилируется с модулем client.c для получения исполняемой программы клиента.


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


$ logger

После чего при запуске клиента 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. После получения отклика заглушка клиента извлекает возвращенное значение, преобразует его и возвращает в головную программу клиента

Цель данной статьи - обсудить терминологию. Статья - не о том, как и для чего, а только исключительно об использовании терминологии. Статья отражает мнение автора и не претендует на научность.

Вступление

Если вы работаете в области программирования распределенных систем или в интеграции систем , то большая часть изложенного здесь вам не в новинку.

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

Терминология

Четкой терминологии и классификации в этой области нет. Используемая ниже терминология является отражением модели, сложившейся у автора, то есть она строго субъективна. Любая критика и любые обсуждения приветствуются.

Я разделил терминологию на три области: RPC (Remote Procedure Call), Messaging и REST. Эти области имеют под собою исторические корни.

RPC

RPC технологии - наиболее старые технологии. Наиболее яркие представители RPC, это - CORBA и DCOM .

В те времена в основном приходилось связывать системы в быстрых и относительно надежных локальных сетях. Главная идея RPC была в том, чтобы сделать вызов удаленных систем очень похожим на вызов функций внутри программы. Вся механика удаленных вызовов пряталась от программиста. По крайней мере её пытались спрятать. Программисты во многих случаях вынуждены были работать на более глубоком уровне, где появлялись термины маршалинг (marshalling ) и unmarshalling (как это по-русски?), что по сути означало сериализацию. Обычные вызовы функций внутри процессов обрабатывались на вызывающей стороне в Proxy , а на стороне системы, выполняющей функцию, в Dispatcher . В идеале ни вызывающая система, ни обрабатывающая система не занимались тонкостями передачи данных между системами. Все эти тонкости сосредотачивались в связке Proxy - Dispatcher, код которых генерировался автоматически.

Поэтому вы не заметите, не должны заметить, никакой разницы между вызовом локальной функции и вызовом удаленной функции.
Сейчас наблюдается своеобразный ренесанс RPC, наиболее яркие представители которого: Google ProtoBuf, Thrift, Avro.

Messaging

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

Появились технологии веб-сервисов . Мы стали говорить ABC: Address, Binding, Contract . Не совсем понятно, почему появились контракты, которые по сути являются Envelope (конвертами) для входных аргументов. Контракты чаще усложняют всю модель, чем упрощают ее. Но… неважно.

Теперь программист явным образом создавал сервис (Service ) или клиента (Client ), вызывающего сервис. Сервис представлял из себя набор операций (Operation ), каждая из которых на входе принимала запрос (Request ) и выдавала ответ (Response ). Клиент явным образом посылал (Sent ) запрос, сервис явным образом получал (Receive ) его и отвечал (Sent), высылая ответ. Клиент получал (Receive) ответ и на этом вызов завершался.

Так же, как и в RPC, где-то здесь работали Proxy и Dispatcher. И как прежде их код генерировался автоматически и программисту не надо было в нем разбираться. Разве только что, клиент явным образом использовал классы из Proxy.

Запросы и ответы явным образом преобразуются к формату, предназначенному для передачи по проводам. Чаще всего это массив байт. Преобразование называется Serialization и Deserialization и иногда прячется в коде Proxy.
Кульминация messaging проявилась в появлении парадигмы ESB (Enterprise Service Bus) . Никто толком не может сформулировать, что это такое, но все сходятся на том, что данные по ESB движутся в виде сообщений.

REST

В постоянной борьбе со сложностью кода, программисты сделали очередной шаг и создали REST .

Основной принцип REST в том, что операции-функции резко ограничили и оставили только набор операций CRUD: Create - Read - Update - Delete . В этой модели все операции всегда применяются к некоторым данным. Имеющихся в CRUD операций достаточно для большей части приложений. Так как REST технологии в большинстве случаев подразумевают использование протокола HTTP, то команды CRUD отразились на команды HTTP (Post - Get - Put - Delete ) . Постоянно утверждается, что REST не обязательно привязан к HTTP. Но на практике повсеместно используется отражение сигнатур операций на синтаксис HTTP команд. К примеру, вызов функции

EntityAddress ReadEntityAddress(string param1, string param2)

Выразится в таком виде:

GET: entityAddress?param1=value1¶m2=value2

Заключение

Прежде, чем начинать дискуссию по распределенным системам или по интеграции, определитесь с терминологией. Если Proxy всегда будет означать одно и то же в разных контекстах, то, к примеру, request мало что будет значить в терминах RPC, а marshalling вызовет недоумение при обсуждении REST технологий.

В состав операционной системы 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 не устраняются. При всем желании ни командная строка, ни, тем более, вмешательство в реестр на уровне редактирования ключей в таких программных пакетах не предусмотрено.