Удаленные процедуры: вызов удаленных процедур, определение и особенности. Fix: не запускается служба "Удаленный вызов процедур (RPC)" Удаленный вызов процедур

Удалённый вызов процедур (или Вызов удалённых процедур ) (от англ. Remote Procedure Call (RPC) ) - класс технологий, позволяющих компьютерным программам вызывать функции или процедуры в другом адресном пространстве (как правило, на удалённых компьютерах). Обычно, реализация RPC технологии включает в себя два компонента: сетевой протокол для обмена в режиме клиент-сервер и язык сериализации объектов (или структур, для необъектных RPC). Различные реализации RPC имеют очень отличающуюся друг от друга архитектуру и разнятся в своих возможностях: одни реализуют архитектуру SOA , другие CORBA или DCOM . На транспортном уровне RPC используют в основном протоколы TCP и UDP , однако, некоторые построены на основе HTTP (что нарушает архитектуру ISO/OSI, так как HTTP изначально не транспортный протокол).

Реализации

Существуют множество технологий, обеспечивающих RPC:

  • Sun RPC (бинарный протокол на базе TCP и UDP и XDR) RFC-1831 второе название ONC RPC RFC-1833
  • .Net Remoting (бинарный протокол на базе TCP, UDP, HTTP)
  • SOAP - Simple Object Access Protocol (текстовый протокол на базе HTTP) см. спецификацию: RFC-4227
  • XML RPC (текстовый протокол на базе HTTP) см. спецификацию: RFC-3529
  • Java RMI - Java Remote Method Invocation - см. спецификацию: http://java.sun.com/j2se/1.5.0/docs/guide/rmi/index.html
  • JSON-RPC JavaScript Object Notation Remote Procedure Calls (текстовый протокол на базе HTTP) см. спецификацию: RFC-4627
  • DCE/RPC - Distributed Computing Environment / Remote Procedure Calls (бинарный протокол на базе различных транспортных протоколов, в том числе TCP/IP и Named Pipes из протокола SMB/CIFS)
  • DCOM - Distributed Component Object Model известный как MSRPC Microsoft Remote Procedure Call или «Network OLE» (объектно-ориентированное расширение DCE RPC, позволяющее передавать ссылки на объекты и вызывать методы объектов через таковые ссылки)

Принцип

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

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

  • Так как вызывающая и вызываемая процедуры выполняются на разных машинах, то они имеют разные адресные пространства, и это создает проблемы при передаче параметров и результатов, особенно если машины находятся под управлением различных операционных систем или имеют различную архитектуру (например, используется прямой или обратный порядок байтов). Так как RPC не может рассчитывать на разделяемую память, то это означает, что параметры RPC не должны содержать указателей на ячейки нестековой памяти и что значения параметров должны копироваться с одного компьютера на другой. Для копирования параметров процедуры и результата выполнения через сеть выполняется их сериализация .
  • В отличие от локального вызова удалённый вызов процедур обязательно использует транспортный уровень сетевой архитектуры (например TCP), однако это остается скрытым от разработчика.
  • Выполнение вызывающей программы и вызываемой локальной процедуры в одной машине реализуется в рамках единого процесса. Но в реализации RPC участвуют как минимум два процесса - по одному в каждой машине. В случае, если один из них аварийно завершится, могут возникнуть следующие ситуации: при аварии вызывающей процедуры удалённо вызванные процедуры станут «осиротевшими», а при аварийном завершении удалённых процедур станут «обездоленными родителями» вызывающие процедуры, которые будут безрезультатно ожидать ответа от удалённых процедур.
  • Существует ряд проблем, связанных с неоднородностью языков программирования и операционных сред: структуры данных и структуры вызова процедур, поддерживаемые в каком-либо одном языке программирования, не поддерживаются точно так же во всех других языках. Таким образом имеется проблема совместимости, до сих пор не решённая ни с помощью введения одного общепринятого стандарта, ни с помощью реализации нескольких конкурирующих стандартов на всех архитектурах и во всех языках.

Подсистемы

  • Транспортная подсистема

Управление исходящими и входящими соединениями. - поддержка понятия «граница сообщения» для транспортных протоколов, не поддерживающих его непосредственно (TCP). - поддержка гарантированной доставки для транспортных протоколов, не поддерживающих ее непосредственно (UDP).

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

В некоторых реализациях RPC (.NET Remoting) границы подсистем являются открытыми полиморфными интерфейсами, и возможно написать свою реализацию почти всех перечисленных подсистем. В других реализациях (DCE RPC в Windows) это не так.

См. также

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

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

Применение

Значительная часть инструментов удаленного управления операционной системой Windows (Event Viewer, Server Manager, управление печатью, списками пользователей) использует DCE RPC как средство общения по сети между управляемой службой и управляющим приложением пользовательского интерфейса. Поддержка DCE RPC присутствовала в Windows NT с самой первой версии 3.1. Клиенты DCE RPC поддерживались и в облегченной линии операционных системы Windows 3.x/95/98/Me.

Системные библиотеки Windows, предоставляющие возможности такого управления и служашие базовым уровнем для управляюших приложений пользовательского интерфейса (netapi32.dll и отчасти advapi32.dll), на деле содержат в себе клиентский код интерфейсов DCE RPC, осуществляющих это управление.

Это архитектурное решение было предметом активной критики в адрес Microsoft. Универсальные процедуры маршаллинга, присутствующие в DCE RPC, очень сложны и имеют огромный потенциал наличия дефектов, эксплуатируемых в сети путем посылки умышленно искаженного пакета DCE RPC. Значительная часть дефектов безопасности Windows, обнаруженных с конца 90-х до середины 2000-х годов, представляла собой именно ошибки в коде маршаллинга DCE RPC.

Помимо DCE RPC, в Windows активно применяется технология DCOM. Так, например, она используется как средство общения между инструментами управления веб-сервером IIS и собственно управляемым сервером. Полнофункциональный интерфейс общения с почтовой системой MS Exchange Server - MAPI - также основан на DCOM.

Идея вызова удаленных процедур (Remote Procedure Call - RPC) состоит в расширении хорошо известного и понятного механизма передачи управления и данных внутри программы, выполняющейся на одной машине, на передачу управления и данных через сеть. Средства удаленного вызова процедур предназначены для облегчения организации распределенных вычислений.

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

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

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

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

Реализация удаленных вызовов существенно сложнее реализации вызовов локальных процедур.

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

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

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

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

    при аварии вызывающей процедуры удаленно вызванные процедуры станут "осиротевшими", а

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

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

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

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

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

Рис . 3.2. Remote Procedure Call

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

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

Вызов удаленных процедур (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-вызовами, выданными сиротами первого поколения. Перевоплощение. В этом случае все проблемы решаются без использования записи на диск. Метод состоит в делении времени на последовательно пронумерованные периоды. Когда клиент перезагружается, он передает широковещательное сообщение всем машинам о начале нового периода. После приема этого сообщения все удаленные вычисления ликвидируются. Конечно, если сеть сегментированная, то некоторые сироты могут и уцелеть. Мягкое перевоплощение аналогично предыдущему случаю, за исключением того, что отыскиваются и уничтожаются не все удаленные вычисления, а только вычисления перезагружающегося клиента. Истечение срока. Каждому запросу отводится стандартный отрезок времени Т, в течение которого он должен быть выполнен. Если запрос не выполняется за отведенное время, то выделяется дополнительный квант. Хотя это и требует дополнительной работы, но если после аварии клиента сервер ждет в течение интервала Т до перезагрузки клиента, то все сироты обязательно уничтожаются.

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

После перезагрузки компа не запустилась служба "Удаленный вызов процедур (RPC) ". Очень многое зависит от этой службы. В итоге не работает восстановление системы, сетевое окружение, звук, Windows Installer, почти не работает консоль управления (MMC), на панели задач не показываются открытые окна и т.д. и т.п. Попытка ручного запуска приводит к ошибке "Неудается запустить...(RPC) на xxxComp. Ошибка 5: Отказано в доступе ". Антивирус ничего не нашел. Два дня копаний и комп удалось вернуть к жизни.

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

Далее, попытка восстановить параметры службы в реестре. Поскольку regedit.exe работал только на чтение/удаление (еще один побочный эффект), не получилось внести изменения. Да они и не нужны были, т.к. все было верно. Должно выглядеть вот так:

Windows Registry Editor Version 5.00 "Description"="Обеспечивает сопоставление конечных точек и иных служб RPC." "DisplayName"="Удаленный вызов процедур (RPC)" "ErrorControl"=dword:00000001 "Group"="COM Infrastructure" "ImagePath"=hex(2):25,00,53,00,79,00,73,00,74,00,65,00,6d,00,52,00,6f,00,6f,00,\ 74,00,25,00,5c,00,73,00,79,00,73,00,74,00,65,00,6d,00,33,00,32,00,5c,00,73,\ 00,76,00,63,00,68,00,6f,00,73,00,74,00,20,00,2d,00,6b,00,20,00,72,00,70,00,\ 63,00,73,00,73,00,00,00 "ObjectName"="NT AUTHORITY\\NetworkService" "Start"=dword:00000002 "Type"=dword:00000010 "FailureActions"=hex:00,00,00,00,00,00,00,00,00,00,00,00,01,00,00,00,00,00,00,\ 00,02,00,00,00,60,ea,00,00 "ServiceSidType"=dword:00000001 "ServiceDll"=hex(2):25,00,53,00,79,00,73,00,74,00,65,00,6d,00,52,00,6f,00,6f,\ 00,74,00,25,00,5c,00,73,00,79,00,73,00,74,00,65,00,6d,00,33,00,32,00,5c,00,\ 72,00,70,00,63,00,73,00,73,00,2e,00,64,00,6c,00,6c,00,00,00 "Security"=hex:01,00,14,80,a8,00,00,00,b4,00,00,00,14,00,00,00,30,00,00,00,02,\ 00,1c,00,01,00,00,00,02,80,14,00,ff,01,0f,00,01,01,00,00,00,00,00,01,00,00,\ 00,00,02,00,78,00,05,00,00,00,00,00,14,00,8d,00,02,00,01,01,00,00,00,00,00,\ 05,0b,00,00,00,00,00,18,00,ff,01,0f,00,01,02,00,00,00,00,00,05,20,00,00,00,\ 20,02,00,00,00,00,18,00,8d,00,02,00,01,02,00,00,00,00,00,05,20,00,00,00,23,\ 02,00,00,00,00,14,00,9d,00,00,00,01,01,00,00,00,00,00,05,04,00,00,00,00,00,\ 18,00,9d,00,00,00,01,02,00,00,00,00,00,05,20,00,00,00,21,02,00,00,01,01,00,\ 00,00,00,00,05,12,00,00,00,01,01,00,00,00,00,00,05,12,00,00,00 "0"="Root\\LEGACY_RPCSS\\0000" "Count"=dword:00000001 "NextInstance"=dword:00000001

Значение параметра start может отличаться. Изменить реестр все же можно, но при этом нужно загрузиться с MS ERD commander .

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

  • Запустить консоль (Пуск > Выполнить: cmd )
  • cd z:\i386 (там дистрибутив Windows)
  • expand explorer.ex_ %TEMP%\explorer.exe
  • expand svchost.ex_ %TEMP%\svchost.exe
  • Запустить Диспетчер задач (Ctrl+Shift+Esc)
  • Остановить процесс exlporer.exe
  • copy %TEMP%\explorer.exe %SYSTEMROOT% /y
  • Остановить все процессы svchost.exe. Внимание! После этого у вас будет 60 секунд до перезагрузки машины.
  • copy %TEMP%\svchost.exe %systemroot%\system32 /y

Этот финт тоже не дал результатов. Еще вариант: запустить проверку всех защищенных системных файлов с заменой неправильных версий правильными. В консоли выполнить:

sfc /PURGECACHE - Очистка файлового кэша и немедленная проверка файлов
sfc /SCANONCE - Разовая проверка при следующей загрузке

Не помогло.. Тогда совсем брутальный ход - восстановление параметров безопасности. Опять же в консоли:

secedit /configure /cfg %windir%\repair\secsetup.inf /db secsetup.sdb /verbose

После перезагрузки комп заработал, базовые сервисы стартовали. Появился новый косяк (а может он был с самого начала): под моей учеткой не запускался, как минимум, менеджер управления дисками и Windows Installer. Отказано в доступе. Можно через консоль восстановить права доступа к системному диску "по умолчанию":

secedit /configure /db %TEMP%\temp.mdb /Cfg %WINDIR%\inf\defltwk.inf /areas filestore

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

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

Что еще можно было предпринять

Пока комп "болел" вот этого не было в реестре:

"ActiveService"="RpcSs"

Возможно ручное добавление как-то бы изменило ситуацию.

Попытки ручного запуска сервиса, например через команду "net start rcpss " заканчивались ошибкой "Error 5: access denied ". Я предполагаю, отказано в доступе потому, что сервис должен запускаться под учеткой системы - "NT AUTHORITY". В реестре есть такой параметр:

"ObjectName"="NT AUTHORITY\\NetworkService"

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

Еще вариант: использование эксплоита KiTrap0D для получения консоли с правами системы. Об этом эксплоите писали в . Собственно бинарник . Вот только у меня стоят виндовские обновки, так что похоже данный эксплоит уже не работает.

Похожие материалы:

 
Статьи по теме:
Как сделать удобной работу с большим количеством вкладок в браузере
Вы сможете работать за компьютером быстрее, если оптимально расположите окна и вкладки браузера. Как быстро переключаться между окнами Нажмите и удерживайте клавишу Alt . Затем нажмите и удерживайте Tab , пока не откроется нужное окно. Как просматривать д
Установка и удаление AVG Internet Security Антивирус авг как включить компонент программы
В этом уроке мы рассмотрим, как установить бесплатный антивирус AVG. Почему именно бесплатный? Этот и другие вопросы я подробно опишу ниже! Сегодня проводить время в Интернете без защиты очень опасно, особенно новичку. Под защитой я подразумеваю антивир
Проверенные безопасные способы
С целью заработка в интернете многие пользователи запускают каналы на Ютубе. Идея хорошая, только без качественных роликов и грамотной раскрутки, никогда не получится зарабатывать большие деньги. Контент играет ключевую роль, а публикуя
Сервисы распознования капчи Автоматическое распознавание капчи
Здравствуйте, уважаемые читатели блога сайт. Антикапча (временно это был Антигейт) – это многофункциональная площадка для автоматического распознавания так называемой капчи (защиты от автоматического постинга ботами, а также защиты поисковиков от парсинг