Чтение онлайн

ЖАНРЫ

Интернет-журнал "Домашняя лаборатория", 2007 №6
Шрифт:

Теперь рассмотрим результаты работы нашего приложения. В отдельном консольном окне компилируем сервер (создаем сборку типа ехе) и запускаем его. В другом консольном окне компилируем клиента, задавая ссылку на копию серверной сборки, размещенной в каталоге клиента. Запускаем клиента два раза и видим, что сумма на счете накапливается. Кроме того видим, что сервер и клиент выполняются в различных доменах приложения.

Консоль сервера

>csc /t: exe MyServer.cs

>MyServer.ехе

Server is listening

Server AppDomain = MyServer.exe

Server AppDomain = MyServer.exe

Bye

>

Консоль

клиента

>csc /r: MyServer\MyServer.ехе МуАрр. cs

>MyApp.ехе

Total = 5

Client AppDomain = MyApp.exe

>MyApp.ехе

Total = 10

Client AppDomain = MyApp.exe

>

Несколько комментариев, касающихся удаленных компонентов.

В.NET определены три типа режимов работы удаленных объектов:

1. SingleCall

Удаленный объект активируется на стороне сервера только при получении вызова какого-либо его метода от клиента и по выполнении этого метода сразу же уничтожается.

2. Singleton

Удаленный объект совместно используется несколькими клиентами, сохраняя состояние между вызовами. Для контроля за его жизненным циклом используется распределенная сборка мусора — лизинг. При этом объект получает некоторое время жизни, продлеваемое автоматически после каждого нового вызова. После исчерпания этого времени следует запрос к спонсору объекта (обычно к самому клиенту) о продлении жизни компонента. При отсутствии ответа объект уничтожается. Такой механизм позволяет экономить на коммуникации между клиентом и удаленным сервером.

3. Активируемый клиентом

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

Говоря об удаленных компонентах и сопоставляя .NET с СОМ нельзя не вспомнить об апартаментах. В одном процессе может быть несколько апартаментов, и ссылка на объект, полученная в одном апартаменте, не может непосредственно использоваться в другом апартаменте. Необходимо выполнить ее маршалинг между апартаментами. В.NET такой проблемы нет. Любая объектная ссылка (прокси на удаленный компонент) используется глобально по всему домену приложения.

И наконец необходимо упомянуть о передаче объектов по значению. Это возможно и полезно если объект небольшой. В этом случае клиент получает не прокси на объект, а его копию. Для передачи объекта по значению необходимо, чтобы соответствующий класс был определен с пользовательским атрибутом [Serializable] для использования стандартного метода сериализации, либо можно самостоятельно реализовать интерфейс ISeriaiizabie для задания собственного способа сериализации. Пользовательские атрибуты и вопросы их использования будут рассмотрены далее.

Обработка ошибок

До сих пор мы не рассматривали обработку ошибок. В СОМ каждый метод каждого интерфейса (за исключением методов AddRef и Release интерфейса IUnknown) должен возвращать значение типа HRESULT, говорящее об успехе или

неудаче вызова метода и о причине неудачи.

Получатель этого значения должен его обработать. Но у него не всегда есть возможность сделать это.

В.NET используется технология обработки исключений — блоки try, catch, finally, инициализация исключения — throw.

В нашем распределенном примере при запуске клиента без запуска сервера возникает никем не перехваченная ошибка. Включим часть кода клиента, где происходит работа с сервером, в блок try и добавим блоки catch и finally для задания реакции на ошибки и на выход из блока try.

using System;

using MyServer;

using System. Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Http;

using System.Net;

public class MyApp {

public static void Main {

HttpChannel с = new HttpChannel;

ChannelServices.RegisterChannel(c);

try {

Account a = (Account)Activator.GetObject(typeof(Account),

"http://localhost:8080/Account",

WellKnownObjectMode.Singleton);

a. Add(5);

Console.WriteLine("Total = {0}", a.Totalf));

}

catch(WebException e) {

Console.WriteLine(e.Message);

}

catch(Exception e){

Console.WriteLine(e.Message);

}

finally {

Console.WriteLine("Bye");

}

}

}

Первый блок catch перехватывает специальное исключение WebException, связанное именно с работой http канала, а второй блок catch перехватывает все остальные исключения. Независимо от наличия ошибки и ее типа всегда отрабатывает блок finally.

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

Клиент запущен до запуска сервера

>МуАрр. ехе

The underlying connection was closed: Unable to connect

to the remote server

Bye

>

Клиент запущен после запуска сервера

>МуАрр. ехе

Total = 5

Bye

>

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

Синхронизация

Теперь рассмотрим случай двух клиентов, параллельно посылающих некоторые суммы на один и тот же счет, поддерживаемый нашим сервером.

Вспомним, что в СОМ использовались апартаменты типа STA для объектов, не допускающих параллельный вызов своих методов, и типа МTА для потоко-безопасных объектов. В.NET по умолчанию считается, что все объекты являются потоко-безопасными.

Поделиться с друзьями: