Опубликован: 23.05.2008 | Доступ: свободный | Студентов: 1566 / 391 | Оценка: 4.80 / 4.10 | Длительность: 15:29:00
Специальности: Программист
Самостоятельная работа 1:

Разработка централизованного алгоритма балансировки распределенного приложения

< Лекция 12 || Самостоятельная работа 1: 12 || Самостоятельная работа 2 >

Создание объекта с возможностью удаленного доступа

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

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

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

  • вызываемый удаленно объект;
  • сервер, который будет содержать этот объект удаленного доступа;
  • клиент, который будет использовать объект удаленного доступа.

Архитектура приложения представлена на рисунке.

Клиент будет создавать объект Order и будет думать, что он локален по отношению к процессу клиента. Однако при использовании объекта Order структура удаленного доступа будет упаковывать вызов в сообщение SOAP и передавать его через HTTP порт 8080 на сервер. Сервер будет распаковывать сообщение SOAP, исполнять метод и запаковывать сообщение для возврата сообщения SOAP клиенту. Клиент будет распаковывать ответный вызов, и получать результаты вызова метода.

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

Следующий код предоставляет базовый объект, который будет доступен через удаленный доступ:

using System;
using System.Collections.Generic;
using System.Text;

namespace Order
{
    public class Order:MarshalByRefObject
    {
        private DateTime m_creation;

        public Order()
        {
            m_creation = DateTime.Now;
        }

        public String GetMachineName()
        {
            Console.WriteLine("Order.GetMachineName() called.");
            return String.Format("Order object created at: {0} on {1}", 
                m_creation.ToLongTimeString(), Environment.MachineName);
        }

        public Double CalculateItem(Double cost, int TaxCode)
        {
            Console.WriteLine("Order.CalculateItem() called.");
            switch (TaxCode)
            {
                case 0:
                    return cost;
                case 1:
                    return cost*1.06;
                case 2:
                    return cost*1.12;
                default:
                    throw new Exception("Error!");
            }
        }
    }
}

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

Мы храним время создания объекта, чтобы можно было определить, когда объект был создан. Свойство GetMachineName возвращает имя машины, на которой выполняется код объекта. Имя машины докажет, что объект на самом деле исполняется в процессе сервера. Метод CalculateItem() является небольшим примером бизнеслогики, которая может находиться в классе Order. Очевидно, что для целей демонстрации мы создаем простую функцию. Если бы это был настоящий объект Order, то метод был бы гораздо сложнее; возможно, метод CalculateItem() возвращал бы документ XML, определяющий весь заказ на покупку.

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

Создание сервера

Теперь, когда мы создали объект, нам требуется поместить этот объект на нашем сервере. Объект удаленного доступа требует наличия сервера, который предоставляет этот объект через порт клиентам. Каждый объект удаленного доступа должен быть опубликован на хосте сервера. Хостом может быть IIS, служба Windows или самостоятельно реализованный хост. Для простоты мы создадим наш собственный хост для публикации этого объекта удаленного доступа.

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Remoting;

namespace Server
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Server started.");
            RemotingConfiguration.Configure("server.exe.config");
            Console.WriteLine("Server is running. Press <Enter> to exit.");
            Console.ReadLine();
        }
    }
}

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

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

RemotingConfiguration.Configure("server.exe.config");

Файл server.exe.config имеет следующий вид:

<?xml version="1.0" encoding="utf8" ?>
<configuration>
  <system.runtime.remoting>
    <application>
      <channels>
        <channel ref="http" port="8080"/>
      </channels>  
      <service>
        <wellknown mode="Singleton" type="Order.Order, Order" objectUri="Order.soap"/>
      </service>  
    </application>  
  </system.runtime.remoting>
</configuration>

Структура удаленного доступа читает узел < system.runtime.remoting > и настраивает среду выполнения удаленного доступа в соответствии с его содержимым. Этот настроечный файл должен быть размещен в той же директории, где и server.exe.

В файле указывается, какой канал необходимо открыть для объекта. Так как используется канал HTTP, тэг канала задается следующим образом:

<channel ref="http" port="8080"/>

Мы также должны открыть объект, и для этого имеется два типа создания объекта wellknown и activated. Аналогично объектам СОМ, объекты типа activated могут иметь состояние и их время жизни определяется клиентом. Объекты типа wellknown создаются в процессе сервера и время их жизни определяется сервером.

Имеется два режима объектов wellknown Singleton и SingleCall. В режиме Singleton создается один объект для обработки всех запросов. Объект сохраняется между запросами клиентов. Объекты SingleCall создаются для каждого запроса переданного клиентом. Каждый раз, когда приходит клиентский запрос, создается новый объект, обслуживается запрос клиента, а затем объект удаляется. Объект Singleton великолепно подходит, если вы хотите совместно использовать общие данные для всех запросов клиентов.

Объекты SingleCall не оставляют следов, так как все созданные объекты уничтожаются при завершении обработки запроса.

Вот иллюстрация использования объекта Singleton:

<wellknown mode="Singleton" type="Order.Order, Order" objectUri="Order.soap"/>

Свойство type говорит среде выполнения удаленного доступа, какой объект должен быть опубликован, и объявляется в формате <тип>, <сборка>. Здесь свойство type говорит, что мы хотим опубликовать объект Order из сборки Order.dll. Чтобы это всё правильно работало, сборка Order.dll должна располагаться там, где среда выполнения сможет ее найти. Мы устанавливаем Order.dll в той же физической директории, что и Server.exe. Заметьте, что расширение .dll сборки не указывается.

Свойство objectUri является идентификатором, под которым наш объект будет опубликован. Так как по одному и тому же каналу и порту может вызываться много различных объектов, мы должны дать каждому объекту уникальный идентификатор, чтобы отличать их друг от друга. Мы даем ему расширение .soap, чтобы указать, что этот объект будет использовать форматер SOAP. Так как форматер SOAP является форматером по умолчанию для канала HTTP, мы не должны указывать форматер в этом настроечном файле.

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

Создание клиента

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

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Remoting;

namespace Client
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Клиент создан в {0} на {1}",
                DateTime.Now.ToLongTimeString(),Environment.MachineName);
            RemotingConfiguration.Configure("client.exe.config");
            Order.Order o = new Order.Order();
            Console.WriteLine(o.GetMachineName());
            Console.WriteLine("Итоговая стоимость: {0}",
                o.CalculateItem(12.48,2));
            Console.ReadLine();
        }
    }
}

Чтобы откомпилировать эти приложение, мы должны создать ссылки на объект среды выполнения удаленного доступа и Order.dll. Может показаться странным, что нам требуется ссылка на Order.dll, так как объект исполняется исключительно на сервере. Клиенту, чтобы он мог осуществлять вызов серверного объекта, требуются метаданные из объекта удаленного доступа. Без этих метаданных компилятор и среда выполнения не будут иметь ни малейшего представления, что представляет из себя объект удаленного доступа. Мы также можем получить метаданные с помощью инструмента soapsuds.exe. Для краткости мы будем хранить экземпляр Order.dll на стороне клиента. За дополнительной информацией по вопросам о метаданных обратитесь к документации по .NET SDK и, в частности, по инструменту командной строки soapsuds.exe.

Точно так же, как и на сервере, клиент реализует настроечный файл для получения конфигурации своего объекта удаленного доступа. Файл называется client.exe.config и хранится в той же директории, что и клиентское приложение:

<?xml version="1.0" encoding="utf8" ?>
<configuration>
  <system.runtime.remoting>
    <application>
      <client>
        <wellknown type="Order, Order" url="http://mobil185:8080/Order.soap"/>
      </client>
    </application>
  </system.runtime.remoting>
</configuration>

Рекомендации по выполнению: при выполнении задания следуют использовать волновой алгоритм для структуры – неориентированное дерево. Волновой алгоритм приведен ниже.

Волновой алгоритм для структуры – дерева

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

  1. дерево – связный ациклический граф;
  2. количество вершин в дереве на единицу больше, чем количество ребер;
  3. в нетривиальном дереве имеется, по крайней мере, две вершины, степени которых равны единице; эти вершины называются висячими или терминальными; остальные вершины имеют степень, не меньше 2.

В описываемом алгоритме инициаторами являются все висячие вершины. Любой инициатор может передать маркер только одному соседнему сайту. Любой другой сайт v (не инициатор), имеющий степень deg(v), генерирует маркер только в том случае, если получил маркеры от deg(v) – 1 соседа, т.е. от всех смежных сайтов, кроме одного. Тогда сайт v отправляет маркер тому единственному соседу, от которого маркера еще не было (вполне возможно, что этот сосед просто задержался с передачей).

Если задержавшийся сосед все же передаст маркер, т.е. сайт v получит deg(v) маркеров, то сайт v выполнит процедуру return(OK). Выполнение процедуры return(OK) любым из сайтов завершает работу распределенного алгоритма.

Шаг 1. Маркеры, инициированные висячими вершинами дерева

Рис. l-1. Шаг 1. Маркеры, инициированные висячими вершинами дерева
Шаг 2. Продвижение маркеров по дереву

Рис. l-2. Шаг 2. Продвижение маркеров по дереву
Шаг 3. Заключительное перемещение маркеров

Рис. l-3. Шаг 3. Заключительное перемещение маркеров

Описанный алгоритм не столь очевиден, как алгоритм для кольцевой архитектуры. Поэтому нам нужны гарантии его правильности, а именно, гарантии того, что если какойлибо из сайтов выполнил процедуру return(OK), все остальные сайты vi получили, по крайней мере, по deg(vi) – 1 маркеров и сгенерировали или готовы сгенерировать выходные маркеры.

Рисунки l-2l-3 иллюстрируют на примере некоторого дерева продвижение маркеров. На шаге 2 вершины, уже получившие маркеры, обозначены соответствующими числами. После выполнения шага 3, вершина, обозначенная "a" и имеющая степень 3, получит последние два маркера. Количество полученных маркеров станет равным трем, и будет выполнена процедура return(OK).

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

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

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

Отчетность:

В результате выполнения лабораторной работы должны быть представлены следующие материалы:

  1. Программа;
  2. Исходные тексты;
  3. Презентация работы;
  4. Презентация, в которой освещаются вопросы реализации консервативных алгоритмов.
< Лекция 12 || Самостоятельная работа 1: 12 || Самостоятельная работа 2 >
Дмитрий Полянский
Дмитрий Полянский
Ольга Космодемьянская
Ольга Космодемьянская

Я прошла курс "Распределенные системы и алгоритмы". Сдала экзамен экстерном и получила диплом. Вопрос: можно ли после завершения теста посмотреть все вопросы, которые были на экзамене и все варианты ответов? Мне это необходимо для отчета преподавателю в моем ВУЗе. Заранее спасибо!