Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции OOP c#.doc
Скачиваний:
44
Добавлен:
22.09.2019
Размер:
3.38 Mб
Скачать

3.4. Программная настройка Remoting

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

namespace BSUIR {

public interface ICalc {

double Add(double x, double y);

double Sub(double x, double y);

double Mult(double x, double y);

double Div(double x, double y);

}

}

Скомпилируем интерфейс в динамическую библиотеку ICalc.dll.

В качестве непосредственной реализации интерфейса BSUIR.ICalc рассмотрим класс BSUIR.Calculator:

using System;

namespace BSUIR {

public class Calculator: ICalc {

public Calculator() {

log("Calculator constructor");

}

public double Add(double x, double y) {

log("Add " + x + " + " + y);

return x+y;

}

public double Sub(double x, double y) {

log("Sub " + x + " - " + y);

return x-y;

}

public double Mult(double x, double y) {

log("Mult " + x + " * " + y);

return x*y;

}

public double Div(double x, double y) {

log("Div " + x + " / " + y);

return x/y;

}

public static void log(string s) {

Console.WriteLine("[{0}]: {1}",

AppDomain.CurrentDomain.FriendlyName, s);

}

}

}

Класс Calculator скомпилирован в динамическую библиотеку с именем calc.dll. Для компиляции класса необходимо установить ссылку на сборку ICalc.dll.

Итак, на данном этапе у нас имеются:

  1. интерфейс BSUIR.ICalc, размещенный в отдельной динамической библиотеке ICalc.dll;

  2. класс BSUIR.Calculator, который реализует интерфейс BSUIR.ICalc и размещается в динамической библиотеке calc.dll.

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

Построим сервер для нашего распределенного приложения. Прежде всего, нам необходимо внести некоторые изменения в класс BSUIR.Calculator.

using System;

namespace BSUIR {

public class Calculator: MarshalByRefObject, ICalc {

// далее по коду изменений нет

. . .

}

}

Напомним, что наследование от MarshalByRefObject – это обязательное условие для удаленных типов.

Код настройки сервера будет размещаться в методе Main() консольного приложения (собственно, данное приложение и будет сервером1). Во-первых, необходимо создать объект, описывающий канал. Воспользуемся классом HttpChannel (пространство имен System.Runtime.Remoting.Channels.Http) для создания стандартного канала на основе протокола HTTP:

HttpChannel chan = new HttpChannel(6000);

Параметром конструктора является номер порта, с которым связан канал (канал прослушивает данный порт).

Созданный канал должен быть зарегистрирован в инфраструктуре. Для этого используется статический метод RegisterChannel() класса ChannelServices из пространства имен System.Runtime.Remoting.Channels:

ChannelServices.RegisterChannel(chan);

После создания и регистрации канала требуется зарегистрировать класс, объекты которого предполагается использовать удаленно. Для регистрации класса используются статические методы класса RemotingConfiguration. В нашем примере будут использоваться объекты с серверной активацией в режиме SingleCall:

RemotingConfiguration.RegisterWellKnownServiceType(

typeof(Calculator),

"theEndPoint",

WellKnownObjectMode.SingleCall);

Параметры метода: тип регистрируемого класса; строка, представляющая концевую точку для типа; элемент перечисления WellKnownObjectMode, указывающий на режим использования серверных объектов (Singleton или SingleCall).

После регистрации канала и удаленного типа сервер переводится в режим ожидания. Полный текст сервера приведен ниже:

using System;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Http;

using BSUIR;

class CalcServer {

public static void Main() {

HttpChannel chan = new HttpChannel(6000);

ChannelServices.RegisterChannel(chan);

RemotingConfiguration.RegisterWellKnownServiceType(

typeof(Calculator),

"theEndPoint",

WellKnownObjectMode.SingleCall);

Console.WriteLine("Press [enter] to exit...");

Console.ReadLine();

}

}

При компиляции сервера необходимо установить ссылку на сборку calc.dll и сборку ICalc.dll.

Приступим к написанию клиента. Как и сервер, клиент будет консольным приложением, логика работы которого сосредоточена в методе Main().

Клиент должен зарегистрировать канал. При вызове конструктора канала на клиенте можно использовать 0 в качестве параметра или применить конструктор без параметров. В последнем случае клиент не сможет принимать вызовы сервера. Это не всегда приемлемо (например, при работе со спонсорами, асинхронных вызовов методов и т. п.).

HttpChannel chan = new HttpChannel(0);

ChannelServices.RegisterChannel(chan);

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

object obj = RemotingServices.Connect(typeof(ICalc),

"http://localhost:6000/theEndPoint");

Получить ссылку на удаленный объект можно при помощи метода Activator.GetObject(). Использование данного метода понятно из примера:

object obj = Activator.GetObject(typeof(ICalc),

"http://localhost:6000/theEndPoint");

После запроса полученную ссылку требуется привести к типу ICalc, а затем можно вызывать методы удаленного объекта:

ICalc calc = (ICalc)obj;

calc.Add(3, 4);

Полный листинг клиента приведен ниже:

using System;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Http;

using BSUIR;

class CalcClient {

public static void Main() {

HttpChannel chan = new HttpChannel(0);

ChannelServices.RegisterChannel(chan);

object obj = RemotingServices.Connect(typeof(ICalc),

"http://localhost:6000/theEndPoint");

ICalc calc = (ICalc)obj;

calc.Add(3, 4);

}

}

Для программной настройки инфраструктуры Remoting применялся класс RemotingConfiguration. Подробное описание свойств и методов этого класса приведено в таблице. Все свойств и методы являются статическими.

Таблица 18

Статические элементы класса RemotingConfiguration

Имя элемента

Описание

ApplicationId

Строка, содержащая GUID для приложения

ApplicationName

Строка с именем приложения. Является частью URI удаленного CAO-типа для клиентов

Configure

Метод используется в случае, когда настройки Remoting хранятся в конфигурационном файле

GetRegisteredActivatedClientTypes

GetRegisteredActivatedServiceTypes

GetRegisteredWellKnownClientTypes

GetRegisteredWellKnownServiceTypes

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

IsActivationAllowed

Метод проверяет на сервере, является ли тип, указанный в качестве параметра, типом с клиентской активацией

IsRemotelyActivatedClientType

Метод проверяет на клиенте, является ли тип, указанный в качестве параметра, типом с клиентской активацией

IsWellKnownClientType

Метод проверяет на клиенте, является ли тип, указанный в качестве параметра, типом с серверной активацией

ProcessId

Строка, содержащая уникальный GUID текущего процесса

RegisterActivatedClientType

RegisterActivatedServiceType

RegisterWellKnownClientType

RegisterWellKnownServiceType

Набор методов для регистрации типов различных видов на клиенте и на сервере