Отдалечени извиквания с. Net remoting



страница2/3
Дата09.06.2017
Размер499.7 Kb.
#23191
1   2   3

Remoting сценарии


Освен Remoting системата, .NET Framework предоставя и други начини за взаимодействие между обекти в различни домейни на приложението (application domains). Всеки от тях е създаден с определена цел, гъвкавост и изисквания към програмистите, които го ползват.

Най-големият конку­рент на Remoting технологията са уеб услугите. Поради това, че те използват HTTP протокола и SOAP сериализация, те много приличат на Remoting решение, използващо HTTP канал и SOAP форматер. От своя страна Remoting технологията ни позволява да поста­вим асемблитата, които съдържат типовете, които ще използваме като отдалечени в IIS. Приликите между двете технологии не се изчерпват само с разгледаното до тук. Възниква въпросът, в кои случаи кое решение е по-удачно.



При избор на технология за конкретна ситуация, трябва преценим доколко сме опитни във всяка една от тях и доколко тя ще бъде удобна за работа. Нека разгледаме критерии, по които да се ръководим при вземането на такова решение, по ред на техния приоритет.

  1. Изисквания към сигурността: когато трябва да криптираме данните и извикванията и/или да автентикираме потребителите, е добре да използваме HTTP базирано приложение, което се намира в IIS. По този начин използваме средствата, които IIS предлага и намаляваме част от отговорността и натоварването от себе си. Имаме свободата да изпол­зваме както уеб услуги така и Remoting. Ако решим да използваме Remoting извън IIS, то трябва сами да се погрижим да защитим своите данни и код.

  2. Производителност: като цяло Remoting технологията е по-бърза и по-производителна от своите конкуренти. Най-добрата комбинация за случая е TCP канал с бинарна сериализация. Уеб услугите биха били по-добър избор, когато нямаме нужда от характерните за Remoting възможности, а сме задължени да използваме HTTP канал със SOAP сериализация.

  3. Съвместимост: при такива изисквания изборът ни са уеб услугите. Remoting технологията е оптимизирана за работа с .NET клиенти. За да се постигне по-добра съвместимост с други технологии (Java, PHP, C++ и др.) трябва да се използва SOAP фор­матиране на съобщенията, което накланя везните в полза на уеб услугите. Въпреки това можем да поставим нашето Remoting приложение в IIS, да използваме HTTP канал и SOAP форматер и да се възползваме от сигурността и мащаби­руемостта, която той предлага.

  4. Мащабируемост (scalability): в този случай единствената препоръка е да се използва IIS като среда за изпълнение, независимо дали сме се спрели на Remoting или уеб услуги.

  5. Функционалност на CLR: чрез Remoting можем да използваме по-пълно възможностите на .NET Framework. Някои от тях не са на разполо­жение при уеб услугите, като например:

  • интерфейси

  • контекст на извикването

  • свойства

  • индексатори

  • управлявани разширения за С++

  • идеално съответствие между всички типове използвани от клиента и сървъра

  • делегати

  1. Обектно-ориентиран дизайн на приложението: XML уеб услугите не отговарят напълно на обектно-ориентирания дизайн. Като цяло те са уеб ресурси, които подобно на уеб страниците стандартно не поддър­жат състоя­ние. За разлика от тях Remoting обектите са обекти в пълния смисъл на думата. Като резултат тази технология има следните обектно-ориентирани възможности, които отсъстват уеб услугите:

  • обектни референции към отдалечени обекти

  • няколко възможности за активиране на обект

  • обектно-ориентирано управление на състоянието

  • разпределено управление на живота на обектите

Това са ключовите точки, които трябва да се обмислят при избора на технология за реализация на приложение, което използва отдалечени обекти. Като обобщение на всичко до тук, нека разгледаме поотделно всяка една от наличните технологии за тази цел.

Чиста мрежова комуникация


Използвайки класовете от пространството с имена System.Net можем да изградим от нулата своя собствена система за комуникация. Можем да имплементираме свои собствени канали, форматери, протоколи и т.н. Проблемът с този подход е, че се работи на ниско ниво и се хвърлят много усилия за "преоткриване на топлата вода".

XML уеб услуги


Ако ще разработваме уеб приложение и разполагаме с възможностите на ASP.NET, то XML уеб услугите са почти винаги правилният избор. Ползва­нето на отворените стандарти XML и SOAP ги прави изключително съвмес­тими, но в някои случаи това е минус, тъй като няма идеално съответствие между типовете, които клиентите използват, за да извлекат данните.

.NET Remoting


Тази система за комуникация е гъвкава, разширяема и не изисква писането на много код. Можем да я използваме и по начин, подобен на уеб услугите. Преимуществата, които тя предлага са:

  • възможност за публикуване и използване на сървърни обекти, от който и да е тип в произволен application domain (конзолно прило­жение, Windows или уеб приложение, уеб услуга).

  • запазване на съответствието на типовете при бинарна сериализация

  • възможност за предаване на обекти по референция

  • контрол над процеса на активация и живот на обектите

  • възможност да използваме разработени от трети страни канали и протоколи, за да разширим начините за комуникация

  • възможност за директно участие в процеса на комуникация и да го управляваме според нашите нужди

Remoting сървър и клиент – пример


Време е да разгледаме на практика как изглежда едно приложение, което използва Remoting. Ще реализираме просто конзолно приложение от тип клиент/сървър, което ще обслужва библиотека с книги. Приложението се състои от две части – Remoting сървър и Remoting клиент.

Кодът на приложението е разпределен в три проекта в едно VS.NET решение (solution):



  • CommonTypes – в този проект се намират общите типове, които клиентът и сървърът ще използват.

  • LibraryServer – сървърното приложение, което ще ни осигурява достъп до отдалечените обекти.

  • LibraryClientклиентското приложение, което осъществява достъп до отдалечената библиотека.

Създаване на общите типове


За да реализираме нужната функционалност се нуждаем от следните типове:

  • Book – представлява една книга. Има три частни полета – име, автор и ISBN. Достъпът до тях се осъществява чрез публични свойства. За да можем да следим изпълнението на приложението при извикването на тези свойства се отпечатва съобщение в конзолата на приложе­нието. Класът наследява MarhalByRefObject, поради което на клиен­та се предоставя отдалечена референция и всички извиквания се извършват на сървъра. Класът изглежда по следния начин:

    Book.cs

    using System;
    namespace CommonTypes

    {

    public class Book : MarshalByRefObject



    {

    private string mAuthor;

    private string mTitle;

    private string mIsbn;


    public string Author

    {

    get



    {

    Console.WriteLine("Book's author retrieved.");

    return mAuthor;

    }
    set

    {

    mAuthor = value;



    Console.WriteLine("Book's author updated.");

    }

    }


    public string Title

    {

    get



    {

    Console.WriteLine("Book's title retrieved.");

    return mTitle;

    }
    set

    {

    mTitle = value;



    Console.WriteLine("Book's title updated.");

    }

    }


    public string Isbn

    {

    get



    {

    Console.WriteLine("Book's ISBN retrieved.");

    return mIsbn;

    }
    set

    {

    Console.WriteLine("Book's ISBN updated.");



    mIsbn = value;

    }

    }


    public Book(string aAuthor, string aTitle, string aIsbn)

    {

    mAuthor = aAuthor;



    mTitle = aTitle;

    mIsbn = aIsbn;

    }

    }

    }



  • Library – класът представлява библиотека от книги. Съдържа масив от всички книги в библиотеката и публичен метод, който осигурява тяхното извличане. В приложението трябва да има една единствена инстанция на този клас, т.е. Library e Singleton обект. Класът също наследява MarhalByRefObject и се маршализира по референция. За да осигурим безкраен живот на обекта, предефинираме метода InitializeLifetimeService() на базовия клас, като му указваме да връща винаги null. Класът изглежда така:

Library.cs

using System;
namespace CommonTypes

{

public class Library : MarshalByRefObject



{

private Book[] mBooks;


public Library()

{

Console.WriteLine("Library object activated.");



mBooks = new Book[]

{

new Book("Steve McConnell", "Code Complete 2",



"0735619670"),

new Book("Svetlin Nakov",

"Internet Programming in Java", "9547753053"),

new Book("Martin Fowler", "Refactoring: Improving " +

"the Design of Existing Code", "0201485672")

};

}


public Book[] GetBooks()

{

Console.WriteLine("Library.GetBooks() called.");



return mBooks;

}
public override object InitializeLifetimeService()

{

return null;



}

}

}


Създаване на сървър


Имплементацията на сървъра не е сложна. Той представлява конзолно приложение, чиято отговорност е да предоставя отдалечени обекти на клиентите.

Основните стъпки при неговата реализация са следните:



  1. Регистриране на канал – регистрираме TCP канал на порт 12345 с подразбиращия се бинарен форматер.

  2. Регистриране на типовете отдалечени обекти – регистрираме типа CommonTypes.Library като Singleton обект със сървърна актива­ция.

  3. Замразяваме изпълнението на сървърното приложение, за да пре­дотвратим неговото завършване, тъй като ако сървърът завърши своето изпълнение, отдалечените обекти стават недостъпни. Не трябва да ни обърква фактът, че сме "приспали" главната нишка на самото приложение, защото неговата единствена цел е да регист­рира каналите и типовете, които клиентите ще използват. Всички останали манипула­ции, свързани с комуникацията между отдалече­ните обекти и клиента, се извършват автоматично от Remoting инфраструктурата в нишки, различни от главната.

Кодът на сървърното приложение е следният:

LibraryServer.cs

using System;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Tcp;
using CommonTypes;
namespace LibraryServer

{

class LibraryServer



{

const int LISTENING_PORT = 12345;

static void Main()

{

// Create the Remoting TCP channel and register it



TcpChannel channel = new TcpChannel(LISTENING_PORT);

ChannelServices.RegisterChannel(channel);

// Register the Library class as singleton server // activated object

RemotingConfiguration.RegisterWellKnownServiceType(

typeof(CommonTypes.Library), "Library",

WellKnownObjectMode.Singleton);

Console.WriteLine("Library remoting server is " +

"listening on TCP port {0}", LISTENING_PORT);

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

Console.ReadLine();

}

}

}


Създаване на клиент


Клиентското приложение е аналогично на сървърното. Отново за простота използваме конзолно приложение, което ще има за цел да извлече данните за всички книги от библиотеката на сървъра, после да промени автора на една от тях и да отпечата данните за всички книги в конзолата. Отново минаваме през стандартните стъпки при работа с Remoting:

  1. Регистриране на канал – регистрираме TCP канал на порт 12345 със подразбиращия се бинарен форматер. Трябва каналите от двете страни на комуникацията да са едни и същи, за да може тя да се осъществи успешно.

  2. Активиране на отдалечен обект – клиентът получава референция към единствената инстанция, която е на сървъра, и от тук нататък може да работи с нея сякаш е локална за приложението.

  3. Използваме отдалечения обект, както локален – в случая извикваме метода GetBooks() на класа Library и след това осъществяваме достъп до свойствата на класа Book.

LibraryClient.cs

using System;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Tcp;
using CommonTypes;
namespace LibraryClient

{

class LibraryClient



{

public static void Main()

{

// Create new client TCP channel and register it



TcpChannel channel = new TcpChannel();

ChannelServices.RegisterChannel(channel);

Console.WriteLine("Registered new client TCP channel.");

// Activate the Library remote object

Library remoteLibrary = (Library)

Activator.GetObject(typeof(Library),

"tcp://localhost:12345/Library");

Console.WriteLine("The Library object activated.");


// Retrieve the books from the server

Book[] books = remoteLibrary.GetBooks();


// Update the first book (through a server call)

books[0].Author = "Author changed";


// Print books (through a series of server calls)

foreach (Book book in books)

{

Console.WriteLine("(Author: {0}; Title: {1}, ISBN: {2})", book.Author, book.Title, book.Isbn);



}

}

}



}

Трябва да обърнем внимание на последните редове на Main() метода на клиента – тези с цикъла за обхождане на всички книги в библиотеката. Тъй като книгите се маршализират по референция всяко обръщение към техен метод или свойство се реализира като обръщение към сървъра. Когато се извършват по няколко такива в цикъл е възможно да загубим доста от производителността на приложението си. Този цикъл е типично тясно място в изпълнението на програмата и е добре той да бъде оптимизиран. Това може да са осъществи като направим типа Book да се маршализира по стойност. По този начин клиентът ще работи с локални копия на всяка книга и ще си спестим многото отдалечени извиквания в цикъла. Това решение обаче не трябва да се прилага сляпо навсякъде, защото води до промяна в поведението на обектите от тип Book, тъй като при промяна на техните свойства се модифицира само локалното им копие при клиента.

Сървърът и клиентът в действие


След компилиране и стартиране на сървърното приложение получаваме следния резултат:

Сървърът е успешно стартирал, регистрирал е типа Library като отдале­чен обект и очаква своите клиенти. Ако в този мо­мент компилираме и стартираме клиентското приложение, ще получим следния резултат:



Вижда се, че клиентът успешно е обновил автора на първата книга и е извлякъл от сървъра списъка на всички книги от библиотеката. След при­ключване на работата на клиента, конзо­лата на сървъра изглежда по следния начин:



Това показва, че клиентът успешно е активирал Library обекта, след което е извикал методът му GetBooks(). След това е обновена една от книгите и информацията за всяка от тях (заглавие, автор и ISBN) е била извлечена. Понеже класът Book използва маршализация по референция, всеки достъп до свойство от този клас от страна на клиента се изпълнява чрез отдалечено извикване на сървъра.


Пример за маршализация по стойност


Нека сега направим малка промяна в класа Book, който се използва от сървъра, и да го направим да се маршализира по стойност. Трябва да заменим реда:

public class Book : MarshalByRefObject

със следния ред:

[Serializable] public struct Book

Нека прекомпилираме сървъра и пак стартираме първо сървъра, а след това клиента. Конзолата на клиента след успешното му изпълнение из­глежда по следния начин:

Ясно се забелязва, че достъпът до свойствата на класа Book вече се изпълняват локално при клиента, а не на сървъра. Това е така, защото класът Book след промяната се маршализира по стойност и не извършва отдале­чено извикване при всеки достъп до негово свойство. Ето как изглежда и сървърът след успешното изпълнение на клиента:



Забелязва се, че въпреки активната работа с обектите от класа Book, извлечени чрез метода GetBooks(), сървърът не отпечатва нищо при достъпа до техните свойства. Това е така, защото работата с тях се извършва при клиента, понеже тези обекти се маршализират по стойност.

Ако с дебъгера на VS.NET проверим състоянието на книгите на сървъра, ще установим, че авторът на първата книга не е променен, въпреки, че клиентът го променя изрично. Това е така, защото клиентът променя само локал­ното си копие на този обект (заради маршализацията по стойност).


Каталог: dotnetcourse -> Beta1
Beta1 -> Изграждане на графичен потребителски интерфейс с Windows Forms
Beta1 -> Асемблита и разпространение
Beta1 -> Управление на паметта и ресурсите
Beta1 -> Уеб услуги с asp. Net
dotnetcourse -> Кратко ръководство и полезни съвети за това как да разработим своя практически проект
dotnetcourse -> Въпрос: Кога е нужно да слагам в класовете си свойства, и кога мога да слагам публични полета? Не е ли вторият вариант по-удобен, особено когато едно поле не се валидира по никакъв начин? Отговор
Beta1 -> Сериализация на данни


Сподели с приятели:
1   2   3




©obuch.info 2024
отнасят до администрацията

    Начална страница