ОБЪЕКТНО-ОРИЕНТИРОВАННЫЙ ОБЕСПЕЧЕНИЕ ПОДХОД И СЕТЕВОЕ ПРОГРАММНОЕ А.И.Илюшин, Н.Б.Дерябин, Журнал «ПРОГРАММИРОВАНИЕ» №6,1990 1.ВВЕДЕНИЕ Использование объектно-ориентированнного подхода, как нам кажется, дает существенные результаты практически во всех областях программирования. Не является исключением и сетевое программное обеспечение. В ИПМ АН СССР накоплен довольно большой опыт создания и использования сетей ЭВМ с объектно-ориентированной архитектурой. В период с 1976 г. по 1981 г. были сделаны пробные реализации и построена объектно -ориентированная сетевая архитектура, которая и используется по настоящее время[1,2]. В 1983 г. была введена в эксплуатацию сеть СЕКОП из ЭВМ БЭСМ-6, реализованная в соответствии с этой архитектурой. В 1988 г. была готова первая реализация сети с объектно-ориентированной архитектурой для IBM PC, ДВК и ЕС ЭВМ. Эта сеть получила название РУСЛАН и в настоящее время продолжает развиваться. Исходя из нашего опыта, по-видимому, можно сделать два основных вывода: - производительность программиста при создании распределенных программных систем в сети с объектно-ориентированной архитектурой принципиально выше по сравнению с работой в сети с традиционной архитектурой. Здесь под традиционной сетевой архитектурой понимается представление распределенной программной системы в виде совокупности распределенных по различным ЭВМ процессов. Причем эти процессы взаимодействуют друг с другом, обмениваясь сообщениями с помощью примитивов "послать - принять". Создавая распределенную систему, программист вынужден строить частные протоколы связи между своими процессами, что является нетривиальной задачей по крайней мере для программиста, привыкшего к традиционному локальному программированию. В сети с объектно-ориентированной архитектурой распределенная программная система строится в виде совокупности объектов-исполнителей операций, распределенных по различным ЭВМ. Эти объекты взаимодействуют путем вызова операций друг в друге. В этом случае локальный и удаленный вызовы операций синтаксически неразличимы в тексте программы. Сеть, как средство, связи превращается просто в один частный случай механизма связи между вызывающей и вызываемой программами. Как следствие сложность локального и распределенного программирования при прочих равных условиях становится практически одинаковой; - производительность во время счета и требования к ресурсам в сети с объектноориентированной архитектурой как минимум не хуже по сравнению с сетью, основанной на "послать-принять". Принципы построения сети с объектно-ориентированной архитектурой, разработанной в ИПМ АН СССР, интерфейсы для пользователей, сетевой протокол удаленного вызова операций описаны достаточно подробно в ранее опубликованных работах [1,2,3,4,5]. В данной статье нам хотелось бы остановиться в основном на другой стороне проблемы обратном влиянии сетевой архитектуры на объектно-ориентированные средства. Дело в том, что распространение некоторого метода за пределы области, в которой он первоначально возник, часто приводит к полезному обобщению этого метода, очищению его от частных решений, которые естественным, однако логически не обязательным, образом были привнесены в него из исходной области применения. Как нам кажется, в объектно-ориентированном подходе именно так обстоит дело с динамическим связыванием, ссылками на объекты, а также со способом создания, хранения и адресации объектов. В сетевой обстановке перечисленные проблемы по необходимости должны решаться способом, отличным от тех, которые используются в известных нам локальных реализациях (см., например, [6]). До рассмотрения именно различий локального и распределенного случаев нам необходимо хотя бы кратко описать распределенный случай объектно-ориентированного подхода. Некоторое количество локальных реализаций объектно-ориентированного подхода считается известными. 2.ОБЪЕКТНО-ОРИЕНТИРОВАННАЯ СЕТЕВАЯ АРХИТЕКТУРА Начнем с перечисления проблем, которые должны быть решены в рамках любой архитектуры для распределенной обработки: - адресация в пределах сети компонент распределенной системы (программ и данных); - связывание удаленных компонент в единую систему. В локальном случае в качестве аналога такого механизма можно, например, указать загрузку подпрограммы из библиотеки по имени в вызывающей программе; - преобразование представления данных для разных ЭВМ, ОС и языков; - нейтрализация сбоев и отказов. С одной стороны, сбои и отказы гораздо более вероятны в распределенном случае по сравнению с локальным, а с другой стороны, благодаря доступности многих ЭВМ, возможно продолжение счета даже в случае отказа отдельных узлов сети; - параллелизм выполнения, который является реальным в отличие от имитируемого в случае одной ЭВМ. Рассмотрим объектно-ориентированную сетевую архитектуру, использованную при разработке сети РУСЛАН. Прикладной уровень строится в виде множества объектовисполнителей операций, которые взаимодействуют путем вызова операций друг в друге. Удаленный вызов операций поддерживается с помощью единственного протокола УДВ. Этот протокол в данной архитектуре заменяет собой протоколы общего назначения на прикладном уровне модели ISO/OSI [7], а также протоколы 6, 5 и 4 уровней этой модели. Протоколы нижележащих уровней можно считать неспецифичными для моделей. Потенциально бесконечное множество прикладных протоколов для частных применений модели ISO/OSI заменяются просто конкретными прикладными подсистемами (объектамиисполнителями), взаимодействие которых, вообще говоря, не несет никакой сетевой специфики. Для программирования распределенных сетевых систем естественно использовать широко распространенные языки, например такие, как Си и Фортран, расширив их соответствующими средствами. При объектно-ориентированном расширении языков для распределенной обработки были использованы следующие понятия: - переменная типа объект-исполнитель операций. Под типом здесь понимается набор имен операций, которые может выполнять объект, указываемый данной переменной. Значением такой переменной является ссылка на объект-исполнитель, который расположен возможно в удаленной ЭВМ. В данном изложении нам удобно называть переменными также и формальные параметры процедур (подпрограмм); - кластер, являющийся реализацией типа объекта-исполнителя. Кластер представляет собой набор подпрограмм, реализующий операции данного типа. Для этого набора подпрограмм в заголовке кластера определяются общие переменные, называемые представлением объекта; - экземпляр объекта-исполнителя или просто объект-исполнитель. Создается из кластера и индивидуального набора значений переменных представления; - файл объектов - это специальный объект, умеющий выполнять операцию "создать объект" с указанным кластером, а также операции "уничтожить", "найти". Значением переменной, заданной в качестве параметра-результата операции создания исполнителя, становится ссылка на созданный объект. Естественно, что с одним кластером может быть создано много объектов. Существенно, что одной переменной могут быть в разные моменты присвоены ссылки на исполнители с разными кластерами, но, естественно, с соответствующими наборами операций (в объектно-ориентированных языках такое свойство называется полиморфизмом). Единственное условие - набор имен операций, определяющий тип переменной, должен быть подмножеством набора имен операций, реализуемых кластером созданного объекта. Файлы объектов могут располагаться как в оперативной памяти, так и на дисках. Введение файлов объектов - это принципиальный шаг, позволяющий в единой системе программирования естественным образом объединить как традиционные языковые средства, так и некоторые возможности баз данных; - вызов операции в объекте-исполнителе. Вызываемый объект задается переменной типа исполнитель. В качестве параметров вызова могут передаваться как переменные традиционных типов, так и переменные типа "объект-исполнитель операций" (динамическое связывание в терминологии объектно-ориентированных языков). В целом предлагаемая схема функционирования прикладного уровня такова: - имеется множество объектов-исполнителей операций, которые хранятся в файлах объектов. Файлы объектов возможно рассредоточены по различным ЭВМ сети; - имеется множество процессов, выполняющих подпрограммы в кластерах объектов. В момент вызова операции в другом объекте, возможно удаленном, процесс "перетекает" в этот другой объект; - сама совокупность взаимодействующих объектов определяется ссылками, которые хранятся в этих объектах в переменных типа "объект-исполнитель". Получаются эти ссылки как аргументы или результаты вызовов операций. В данной модели объекты и процессы находятся в соотношении "много - много". А именно, один процесс может проходить через много объектов, расположенных в разных ЭВМ. Конкретно это означает наличие распределенного по этим ЭВМ стека для вложенных вызовов подпрограмм из кластеров объектов. С другой стороны, несколько процессов могут одновременно войти в один объект. При необходимости они могут синхронизоваться на общих переменных представления этого объекта. Для этого достаточен любой известный в локальном случае набор средств. Отметим, что в модели ISO/OSI принято соотношение "один - один". А именно, процесс фактически отождествляется с подсистемой (объектом). Перечислим, как решаются приведенные выше сетевые проблемы, когда распределенная система представляет собой множество исполнителей, взаимодействующих путем вызова операций: - адресация. Значением переменной типа исполнитель является ссылка, указывающая на объект-исполнитель, расположенный в любой ЭВМ сети. В ссылке хранится уникальный в пределах всей сети идентификатор объекта (УИД), перечень указателей на операции, которые может выполнять данный объект, и указатель на сетевую процедуру связи. УИД может быть дополнен различного рода физическими адресами, оптимизирующими доступ. Тогда вызов удаленной операции через рассматриваемую ссылку и процедуру связи попадает в сетевое обеспечение, которое транспортирует его до вызываемого объектаисполнителя и возвращает назад результаты выполнения операции; - связывание объектов-исполнителей в единую систему осуществляется путем передачи ссылок на них как параметров операций. В частности, ссылки могут запоминаться в объектах каталогах и получаться как результаты операций поиска по имени в этих каталогах. Для переменной типа исполнитель всегда хранится перечень имен операций, определяющий, так сказать, формальный тип данной переменной. При занесении в переменную ссылки происходит связывание этой переменной с в общем случае удаленным конкретным объектом-исполнителем. Связывание переменной типа объект-исполнитель при присваивании ей значения с конкретным объектом и следовательно с набором подпрограмм, реализующих операции, перечисленные в типе, можно рассматривать как естественное распространение на объектно-ориентированный и распределенный случаи механизма "знакомств", хорошо известного по системам типа MULTICS; - преобразование представления. В механизм расширения языка программирования объектно-ориентированными средствами входит генерирование по описаниям переменных дескрипторов, описывающих их тип (целый, вещественный, массив, запись, исполнитель и т.д.). Тогда сетевое обеспечение, имея в момент траспортировки вызова тип данных, тип языка и тип ЭВМ, легко преобразует представление; - нейтрализация сбоев. Хранение объектов в файлах объектов (стабильная память), уникальные идентификаторы объектов позволяют естественным образом использовать известную в базах данных технику неделимых цепочек операций, контрольных точек и рестартов. Оказалось очень полезной в распределенном случае обработка исключительных ситуаций, аналогичная локальной обработке. Исключительная ситуация распространяется по цепочке вложенных вызовов "вверх" до обработчика через все ЭВМ, по которым прошел процесс выполнения этих вложенных вызовов; - параллелизм. В приводимой схеме среда связи между ЭВМ оказывается прозрачной для вызовов операций. Сетевое обеспечение с логической точки зрения является лишь некоторой частной реализацией общего механизма вызова операций. Все содержательные действия выполняются внутри исполнителей. Поэтому проблемы создания процессов и их синхронизации сводятся к локальному случаю и могут быть решены с помощью хорошо известных локальных средств, например, семафоров, мониторов и т.д. Сделаем выводы из выше сказанного: - в локальном случае хорошо известные средства создания программных систем как совокупности подпрограмм, вызывающих друг друга, достаточны и удобны. Введение объектов-исполнителей является естественным обобщением (добавляется новый тип исполнитель для переменных и параметров операций) этих хорошо известных средств. Хорошо известные средства управления процессами в локальном случае также достаточны; - распределенный случай сводится к локальному с помощью удаленного вызова операций. Сеть становится одним из частных механизмов связи между подпрограммами. Для программиста, с точки зрения техники программирования, исчезает разница между локальным и распределенным случаями. Он может пользоваться в обоих случаях едиными средствами, исторически доказавшими свою достаточность и удобство. 3. ВЛИЯНИЕ СЕТЕВОЙ ОБСТАНОВКИ НА ОБЪЕКТНО-ОРИЕНТИРОВАННЫЙ ПОДХОД Рассмотрим основные особенности сетевого случая по сравнению с локальным, а также влияние этих особенностей на объектно-ориентированную архитектуру. Как нам кажется, одно из существенных отличий распределенных систем от локальных в настоящее время в том, что при раскрутке распределенных систем часто главная программа запускается позже ряда подсистем, с которыми эта главная программа должна динамически связаться и использовать их. Конечно, и в локальном случае можно найти примеры такой ситуации. Например, операционная система запускается до любой прикладной системы, которая использует ее операции. Однако, операционная система является предопределенным объектом с предопределенным набором операций, и увязка с ними выполняется чаще всего статически. Напротив, в распределенном случае естественно, что в машинах-серверах заранее запускаются разнообразные подсистемы, к которым впоследствии динамически подключаются программы-заказчики. Причем на разных ЭВМ, возможно, имеются функциональные дубли подсистем, поставляемых различными поставщиками, и программа-заказчик может динамически выбрать ту или иную реализацию нужной ей функции. Реализация указанной возможности требует от языка программирования и его поддержки времени счета ряда средств, которые, как нам кажется, отсутствуют в известных нам объектно-ориентированных локальных реализациях. Рассмотрим требуемые средства в порядке, соответствующем естественной последовательности работы в сети ЭВМ. Требуется: - возможность создать подсистему-исполнитель в виде объекта, который может существовать нужный период времени и который может быть найден и использован независимыми программами-заказчиками. Отсюда, естественным образом, по аналогии с файловыми системами и базами данных возникает понятие файла объектов, уникальный идентификатор объекта, ссылка на объект, в которой хранится этот идентификатор, уникальный в пределах сети, каталоги, в которых ссылки на объекты регистрируются под различными именами. В известных нам локальных реализациях объекты создаются традиционными способами: в статической памяти программы, в "автоматической" памяти (стек) и в heap памяти. Стабильная файловая память для объектов отсутствует; - возможность динамически связать программу-заказчик с найденным объектомисполнителем. Отсюда вытекает потребность иметь в качестве значения переменной типа исполнитель достаточно сложную ссылку на объект. В этой ссылке должен храниться набор имен операций, необходимых программе-заказчику, а после связывания с конкретным объектом УИД этого объекта, указатели на процедуры, реализующие операции, и т.д. Здесь важно подчеркнуть, что тип переменной-исполнителя при написании программы-заказчика услуг определяется в виде набора требуемых ей операций возможно путем рассмотрения уже имеющихся подсистем и их наборов операций. При этом выбирается некоторое удобное для данной программы подмножество операций. Именно поэтому в использованной нами архитектуре под типом объекта-исполнителя понимается просто набор имен операций. Это позволяет динамически связать программу-заказчик с любой подсистемой, которая в частности реализует и подмножество операций с этими именами. В таких сравнительно старых языках как Ада и Модула-2 динамическое связывание просто отсутствует. В новых объектно-ориентированных системах на основе языка С++ и в TURBO PASCAL 5.5 фирмы BORLAND динамическое связывание, следуя языку СИМУЛА-67, ограничено соотношением базовый тип в программе-заказчике и производный тип в подсистеме-исполнителе. При этом базовый тип должен быть явно указан в описании производного типа и тем самым должен быть определен до него. Выше было показано, что тип в программе-заказчике часто определяется позже реализации используемого объекта. Главное в данной ситуации то, что механизм динамического связывания программы-заказчика с объектом -исполнителем, как нам кажется, никакого отношения к содержательному понятию "наследования" и "родительского" типа не имеет. Подведем некоторые итоги. Введение понятия файла объектов, трактовка типа переменной-исполнителя, особенности реализации ссылок на объекты явились следствием сетевой специфики и отсутствия соответствующих средств в известных нам локальных реализациях объектно-ориентированных систем. Как нам кажется, указанные средства не являются специфичными именно для распределенного случая и являются естественным обобщением, уместным и для локального случая. В качестве примера возможного применения этих средств в локальном случае укажем на использование стабильной файловой памяти объектов для организации контрольных точек и рестартов, а также для хранения общедоступных подсистем в крупных ЭВМ. 4. ПРИМЕР РАСПРЕДЕЛЕННОГО ПРОГРАММИРОВАНИЯ Приведем пример, который написан на языке СИР2, являющимся объектноориентированным расширением языка СИ. Рассматриваются две программы, возможно расположенные на разных ЭВМ. Программа-исполнитель на той ЭВМ, на которой она выполняется, создает объект-исполнитель с кластером ANYCLUST и затем регистрирует этот объект под именем ANYOBJ в некотором сетевом каталоге, известным в сети под именем PUBLICDIR. Этот каталог возможно расположен на другой ЭВМ. Программазаказчик, выполняющаяся возможно на третьей ЭВМ, находит в сети этот объект и вызывает в нем операцию ANYOPER1. Приводимые ниже программы могут быть выполнены с использованием либо трех, либо двух, либо одной ЭВМ. При этом как исходные тексты программ, так и машинный код (только в случае однотипных ЭВМ) будут идентичными для всех трех случаев. /* ------------ программа-исполнитель /* определение кластера ANYCLUST */ clust ANYOPER1, ANYOPER2 ANYCLUST /* переменные представления объекта */ int ... ; char ... ; serv ... ; и т.п. ; clbody ANYCLUST oper ANYOPER1( ... ) ---------------*/ /* тело функции, реализующей операцию ANYOPER1 */ oper ANYOPER2( ... ) /* тело функции, реализующей операцию ANYOPER2 */ /* Головная функция */ main() /* описание четырех переменных типа объект-исполнитель, указывающих на: - файл объектов текущей задачи - переменная TFO - предопределенный каталог текущей ЭВМ - переменная DIROWN - общесетевой каталог, зарегистрированный в текущей ЭВМ под именем PUBLICDIR, - переменная DIR - вновь создаваемый объект - переменная OBJ */ serv CREATE TFO; serv FIND, ENTER DIR, DIROWN; serv ANYOPER1, ANYOPER2 OBJ; /* Сетевое инициирование */ ninit(); /* Получение ссылок на файл объектов задачи и каталог своей ЭВМ */ get_tfo(res TFO); get_dir(res DIROWN); /* Создание объекта */ TFO.CREATE(res OBJ, ANYCLUST); /* Подключение к сетевому каталогу */ DIROWN.FIND(res DIR, "PUBLICDIR"); /* Регистрация объекта в каталоге */ DIR.ENTER(OBJ, "ANYOBJ"); /* Остаемся резидентом в ожидании вызовов операций */ nkeep(); /* ------------ программа-заказчик ---------------*/ main() serv FIND DIR, DIROWN; serv ANYOPER1 OBJ; /* Сетевое инициирование */ ninit(); /* Получение ссылки на каталог своей ЭВМ */ get_dir(res DIROWN); /* Подключение к сетевому каталогу */ DIROWN.FIND(res DIR, "PUBLICDIR"); /* Поиск объекта в каталоге */ DIR.FIND(res OBJ, "ANYOBJ"); /* Вызов целевой операции */ OBJ.ANYOPER1( ... ); ЛИТЕРАТУРА 1. А.И. Илюшин, и др. Вызов процедур в распределенных системах. Методические материалы и документация по пакетам прикладных программ, вып. 24, ч. 1, Москва, МЦНТИ, 1983, стр. 104-130. 2. A.I.Ilushin, A.N.Myamlin, V.S.Shtarkman, Computer Network Software Design Based on Abstract Objects, Information Processing 83, Paris, 1983, pp. 23-28. 3. С.А.Васильев, и др. Объектно-ориентированные средства для программирования распределенных систем. Методические материалы и документация по пакетам прикладных программ, вып. 31, ч. 1, Москва, МЦНТИ, 1986, стр. 30-57. 4. Дерябин Н.Б., Илюшин А.И. Распределенное программирование на базе языка Си. XIV Всесоюзная школа-семинар по вычислительным сетям. Тезисы докладов. МоскваМинск, 1989, ч.1, стр. 53-58. 5. Савицкая О.А., Илюшин А.И., Дерябин Н.Б. Распределенные вычисления в Фортране. XIV Всесоюзная школа-семинар по выч. сетям. Тезисы докладов. МоскваМинск, 1989, ч.3, стр. 286-290. 6. Bjarne Stroustrup, The C++ Programming Language, Addison-Wesley, 1986, 328 pp. 7. ISO 7498 Information processing systems - Open Systems Interconnection - Basic Reference Model. Телефон для справок: 333-80-55 (Москва)