Э. Таненбаум, М. ван Стеен - Распределённые системы (принципы и парадигмы) (1162619), страница 25
Текст из файла (страница 25)
Однако важность таких параметров делает такое решение абсолютно неподходящим. На самом деле в нем нет особой необходимости.В примере с процедурой read клиентской заглушке известно, что второй параметр указывает на массив символов. Предположим на минуту, что заглушка такжезнает и величину этого массива. После этого вырисовывается следующая стратегия: скопировать этот массив в сообщение и передать его на сервер. Сервернаязаглушка может после этого вызвать сервер, передав ему указатель на этот массив, даже если числовое значение этого указателя будет отличаться от переданного во втором параметре вызова процедуры read. Изменения, которые с помощью указателя сделает сервер (то есть по указанному адресу запишет данные),прямо отразятся на буфере сообщения серверной заглушки.
Когда сервер закон-2.2. Удаленный вызов процедур101чит работу, оригинальное сообщение будет отослано назад, клиентской заглушке, которая скопирует буфер клиенту. В результате вызов по ссылке будет подменен копированием/восстановлением. Несмотря на то что это не одно и то же,часто такой замены вполне достаточно.Небольшая оптимизация позволяет сделать этот механизм вдвое эффективнее. Если обеим заглушкам известно, входящим или исходящим параметромявляется буфер для сервера, то одну из копий можно удалить. Если массив используется сервером в качестве исходных данных (то есть при вызове write), токопировать его обратно не нужно. Если это результат, то нет необходимости изначально передавать его серверу.В качестве последнего комментария отметим, что нет ничего особенно хорошего в том, что мы можем работать с указателями на простые массивы и структуры, если нам по-прежнему недоступна работа с более общими вариантами указателей — с указателями на произвольные структуры данных, например на сложныеграфы.
В некоторых системах делается попытка решить эту проблему путем передачи серверной заглушке реальных указателей с последующей генерацией специального кода в процедурах сервера для работы с этими указателями. Так, дляполучения данных, которые соответствуют указателю, сервер может сделать специальный запрос.Спецификация параметров и генерация заглушекПосле всех этих объяснений становится ясно, что сокрытие механизма удаленного вызова процедур требует, чтобы вызывающая и вызываемая системы договорились о формате сообщений, которыми они обмениваются, и при необходимости пересылки, например, данных сложной структуры, следовали определенномупорядку действрп"!. Другими словами, при совершении RPC обе стороны должныследовать одному протоколу.В качестве простого примера рассмотрим процедуру, показанную на рис.
2.10, а.Она имеет три параметра: символ, число с плавающей точкой и массив из пятицелых чисел. Предполагая, что длина слова составляет четыре байта, протоколRPC может предписать передачу символа в крайнем правом байте слова (оставляя последующие три пустыми), числа с плавающей точкой — в целом слове,а массива — в виде последовательности слов с общей длиной, равной длине массива, и предшествующим словом, содержащим длину последовательности(рис. 2.10, б). Если ввести подобные правила, то клиентская заглушка будетзнать, что для процедуры foobar необходимо использовать тот формат, которыйпредставлен на рис. 2.10, б, а серверная заглушка — что именно такой формат будет иметь входящее сообщение для вызова процедуры foobar.Определение формата сообщения — это только одна сторона протокола RPC.Этого недостаточно.
Также нам необходимо, чтобы клиент и сервер пришли к договоренности по вопросу представления простых типов данных, таких как целыечисла, символы, логические значения и т. д. Так, протокол может предписать,чтобы целые передавались без знака, символы в 16-битной кодировке Unicode,а числа с плавающей точкой — в формате стандарта IEEE 754, и все это — в остроконечном формате. Только при наличии такой дополнительной информациисообщение может быть однозначно интерпретировано.102Глава 2. СвязьЛокальныепараметрыпроцедурыfoobarz[0]foobar( char х; float у; int z[5]){z[1]z[2]z[31z[4]aбРис.
2 . 1 0 . Процедура (a) и соответствующее процедуре сообщение (б)После того как все биты до последнего выстроеР1Ы в ряд по согласованнымправилам кодирования, осталось сделать только одно. Вызывающая и вызываемая системы должны договориться между собой об обмене реальными сообщениями. Например, они могут решить использовать транспортный протокол с соединениями, такой как TCP/IP. Альтернативой ему будет ненадежная службадейтаграмм, в этом случае клиент и сервер должны включить реализацию схемыконтроля ошибок в RPC. На практике возможны различные варианты.После завершения определения протокола RPC необходимо реализовать заглушки — клиентскую и серверную.
К счастью, заглушки, работающие по одному протоколу, для разных процедур различаются лишь интерфейсом с приложениями. Интерфейс состоит из набора процедур, которые могут быть вызваныклиентом, но реализуются на сервере. Доступ к интерфейсу осуществляетсяобычно из определенного языка программирования, одного из тех, на которыхнаписан клиент или сервер (хотя, строго говоря, это не обязательно). Для упрощения работы интерфейсы часто опрюываются с использованием языка определения интерфейсов {Interface Definition Language, IDL). Интерфейс, определенный на чем-то вроде IDL, компилируется затем в заглушки клиента и сервера,а также в соответствующие интерфейсы времени компиляции и времени выполнения.Практика показывает, что использование языка определения интерфейсовделает приложения клиент-сервер, базирующиеся на RPC, существенно проще.Поскольку клиентская и серверная заглушки очень легко сгенерировать полностью автоматически, все системы промежуточного уровня, основанные на RPC,используют IDL для поддержки разработки программного обеспечения.
В некоторых случаях применение IDL просто обязательно. Мы рассмотрим подобныеслучаи в следующих главах.2.2. Удаленный вызов процедур1032.2.3. Расширенные модели RPCУдаленные вызовы процедур стали фактическим стандартом для связи в распределенных системах. Популярность этой модели объясняется ее несомненной простотой.
В этом пункте мы рассмотрим два расширения базовой модели RPC, созданные для разрешения некоторых ее недостатков.ВходыБазовая модель RPC предполагает, что вызывающая и вызываемая системы могут связываться друг с другом для обмена сообш.ениями по сети. В общем случаеэто предположение истинно. Однако рассмотрим вариант, когда клиент и серверустановлены на одной машине.
В стандартном случае мы должны использоватьсредства локального межпроцессного взаимодействия {InterProcess Communication,IPC), которые базовая операционная система предоставляет процессам, запущенным на одной машине. Так, например, в UNIX соответствующие средства включают в себя совместно используемую память, каналы и очереди сообщений (детальное обсуждение IPC в UNIX-системах можно найти в [439]).Локальные средства IPC обычно значительно более эффективны, чем сетевые, даже если последние используются для связи между процессами на одноймашине. Соответственно, если важна производительность, следует совмещатьразличные механизмы межпроцессного взаимодействия, руководствуясь тем, находятся ли процессы, в которых мы заинтересованы, на одной машине или нет.В качестве компромисса некоторые операционные системы предоставляютпроцессам, размещенным на одной машине, эквивалент RPC под названием входов {doors).
Вход — это обобщенное имя процедур, существующих в адресномпространстве процессов сервера, которые могут вызываться процессами, размещенными на одной с сервером машине. Входы впервые появились в операционной системе Spring [297] и были хорошо описаны в [193]. Сходный механизм,под названием упрощенный вызов RPC {lightweight RPC), описан в [49].Вызов входов требует поддержки локальной операционной системы, как показано на рис. 2.11. Так, для того чтобы появилась возможность вызвать вход,процесс сервера должен зарегистрировать его.
При регистрации входа возвращается его идентификатор, который впоследствии можно будет использовать в качестве символического имени входа. Регистрация заканчивается вызовом door_create. Доступ других процессов к зарегистрированному входу может осуществляться просто по тому идентификатору, который мы получили при регистрациивхода. Так, например, в Solaris каждый вход имеет файловое имя, которое можнополучить через идентификатор простым вызовом fattach. Клиент вызывает входчерез системный вызов с1оог_са11, в который идентификатор входа передаетсятак же, как и любой другой обязательный параметр. Затем операционная система производит вызов того процесса, который зарегистрировал вход. Результатомэтого вызова будет вызов входа сервера.
Результаты вызова входа будут возвращены в процесс клиента через системный вызов cloor_return.Главное преимущество входов состоит в том, что они позволяют использовать для связи в распределенных системах единый механизм — вызовы процедур.Глава 2. Связь104К сожалению, разработчики приложений часто нуждаются в сведениях о том,выполняется ли данный вызов в текущем процессе, в другом процессе на этой жемашине или в удаленном процессе.КомпьютерКлиентский процессСерверный процессserve r_door(...){door_return(...);}main(){Регистрация входаfd = open(door_name,...);door_call(fd,...);~^-fd = door_create(...);fattach(fd, door_name,...);И^)Операционная системаmain(){z:XВызов зарегистрированного Возвращение в вызывающийвхода для другого процессапроцессРис.
2 . 1 1 . Принципы использования входов в качестве механизма IPCАсинхронный вызов RPCв стандартном варианте вызова клиентом удаленной процедуры его работа приостанавливается до получения ответа. Когда ответ не нужен, этот жесткий алгоритм «запрос-ответ» не является необходимым, приводя только к блокированиюклиента с невозможностью производить работу до получения ответа от удаленной процедуры.