Vítejte na blog.vyvojar.cz Přihlásit | Registrovat | Pomoc

C# Projects

Malá řešení pro velké projekty.
Pitomoučký .NET Remoting

Mnoho technologií nedojde své slávy jen díky tomu, že od začátku působí na začínající programátory velmi robustně, nabubřele a velmi neprolomitelně. .NET Remoting skutečně je technologií robustní alespoň co se výkonu týče. Za nabubřelý bych jej nepovažoval, ale to možná jen proto, že jsme mu již pod sukně nakouknul a tak trošku jsem poznal, že je to velmi příjemný kámoš. Na pivo s ním sice nepůjdu (pokud se nepočítá pročítání bible remotingu pod názvem .NET Advanced Remoting ve smíchovské pivnici Na Verandách), ale jakmile potřebuji software, který musí komunikovat s jiným software ať už v podobě Windows nebo Web Services, ten 'zmetek' Remoting tam chybět nesmí. Připravil jsem pro ty, kteří se zatím ostýchají vstoupit do těchto vod takový Pitomoučký .NET Remoting příklad. Tak jdeme na to.

Bez trochy teorie to nepůjde takže ve zkratce:

otázka: Jak donutím dva programy, aby si spolu vyměňovali informace?

odpověď: Stav jednoho programu budu ukládat do souboru a druhým programem je budu číst.......????!!!!!!...  Tak tahle odpověď, ta snad patří do blogu pro programátory BAT souborů :)
odpověď: napíšu vlastní TCP Client a TCP Server aplikaci.... ????!!!!!...... Jistě, i tohle může být cesta a někdy jediná správná, ale tohle jsem zrovna slyšet nechtěl.
odpověď: použiju technologii .NET Remoting ..... !!!!! Anoooooo. Správně.

Tak již nechám pokusu o oživení a půjdu dál. Takže Technologie .NET Remoting umožňuje dvěma programům spolu komnunikovat. K tomu aby dva programy spolu dokázali komunikovat, potřebujeme tři objekty:

  • ServerApplication
  • ClientApplication
  • RemoteObject

Jeden bude sedět na serveru, druhý bude dřímat v klientské aplikaci a třetí bude objektem, který budou tyto dva objekty sdílet, resp přes který si obě aplikace budou vyměňovat informace.

Poznámka: Zde bych chtěl upozornit hnidopichy kterým chybí přesné definice a obsáhlé 'nabubřelé' odstavce, že tento příspěvek je pro jejich méně zdatné kolegy, kteří neví jak se rozhoupat. Stick out tongue

Serverová aplikace může být například Windows Service, ale my si vytvoříme aplikaci, kterou spustíme hezky růčo, abysme si nekomplikovali život. Tedy bude to Windows Console aplikace. Klientská aplikace bude aplikací též konzolovou a taktéž jen pro zjednodušení příkladu.

RemoteObject

Začneme objektem, který je nejzajímavější z celé této trojice a tím je RemoteObject, tedy ten posel dobrých i špatných zpráv, zpráv které si vyměňuje Server s Clientem.

 

using System;

 

namespace RemotingTest

{

    public class RemoteObject : MarshalByRefObject

    {

        // private property

        private int _Counter = 0;

 

        // public property

        public int Counter

        {

            get { return _Counter; }

        }

 

        // metoda zvyšující hodnotu proměnné _Counter

        public void InceraseCounter()

        {

            _Counter++;

        }

 

        // překrytí metody bázové třídy která určuje životnost instance objektu

        public override object InitializeLifetimeService()

        {

            return null;

        }

    }

}

 

Tak toto je náš pitomoučký RemoteObject. Hned první věc která zaujme je bázová třída od které je náš RemoteObject odvozen. Jedná se o třídu která umožňuje objektům komunikaci mezi aplikačními doménami právě v aplikacích kde je použita technologie .NET Remoting. Více pro tuto chvíli netřeba vědět. Přepsáním metody InitializeLifetimeService() bázové třídy zajistíme, že instance objektu hned tak nevyprší. Každá taková instance v závislosti způsobu jejího vytvoření má totiž svou životnost a abychom zajistili, že nám nezmizí dríve než ji budeme chtít v našem příkladu použít, přepíšeme tuto metodu tak jak je popsáno výše. Tento objekt nakonec zkompilujeme do samostatné knihovny např: RemoteObject.dll (kupodivu)

Nyní se podíváme na ServerApplication

 

using System;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Tcp;

 

namespace RemotingTest

{

    class Program

    {

        static void Main(string[] args)

        {

            // Vytvoření instance tcp komunikačního kanálu.

            TcpChannel tcpChannel = new TcpChannel(2222);

 

            // zaregistrování kanálu

            ChannelServices.RegisterChannel(tcpChannel, false);

 

            //vytvoření instance RemoteObject

            RemoteObject rObject = new RemoteObject();

 

            // Nabídnutí RemoteObject instance pro okolí na adrese 'tcp://jmenopocitace:2222/RemoteObject.rem'

            ObjRef oRef = RemotingServices.Marshal(rObject, "RemoteObject.rem");

 

            // smyčka pro ovládání serverové části - při stisku klávesy se navýši hodnota proměnné RemoteObject.Counter

            while (true)

            {

                Console.WriteLine("Server Counter:{0}", rObject.Counter);

                Console.ReadKey(true);

                rObject.InceraseCounter();

            }

        }

    }

}

 

Tak a to je celá ServerApplication. Není to tak složité že? Komunikační kanál, registrace, instance objektu a jeho vystavení blízkému i vzdálenému okolí. Vězte však, že jakmile se začnete zabývat .NET Remotingem hlouběji, zjistíte, že toho dokáže o dost více. Dozvíte se mimo jiné, že nemusíte komunikovat například jen po TCP kanálu, ale že to jde i po HTTP a spoustu dalšího. Znovu připomínám, že se jedná o 'Pitomoučký příklad', který má pomoci rozhoupat se těm, kteří to ještě nezkusili. 

No a zbývá už jen ClientApplication

 

using System;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Tcp;

 

namespace RemotingTest

{

    class Program

    {

        static void Main(string[] args)

        {

            // Vytvoření prázdné instance komunikačního kanálu

            TcpChannel tcpChannel = new TcpChannel();

 

            // Jeho zaregistrování

            ChannelServices.RegisterChannel(tcpChannel, false);

 

            // žádost o instanci RemoteObject která byl vytvořena Serverpplication a čeká v serverové aplikaci.

            RemoteObject rObject = (RemoteObject) Activator.GetObject(typeof(RemoteObject), "tcp://localhost:2222/RemoteObject.rem");

 

            // cyklus pro ovládání programu - s každým průchodem ClientApplication přečte hodnotu

            // která je v RemoteObject.Counter jehož instance byla vytvořena v ServerApplication

            while (true)

            {

                Console.WriteLine("Server Counter on Client:{0}", rObject.Counter);

                Console.ReadKey(false);

            }

        }

    }

}

 

Klientská aplikace také není žádná románová kapitola. Povšimněte si, že u klientské aplikace nezadáváme při inicializaci TCP kanálu port na kterém má komunikovat. Mohli bychom, ale v případě že budeme pouštět obě aplikace na stejném stroji pak nesmíme chtít komunikovat po stejném portu jako serverová aplikace. Prostě po stejném portu to nepůjde. Navíc se jedná o klientskou aplikaci a tam je nám jedno jaký port bude v užití. Konstrukce kterou jsem použil prostě vybere 'nějaký volný port'. Port který jsme nastavili na serverové aplikaci nás zajímá až ve chvíli, kdy žádáme o instanci RemoteObject. To je port, na kterém serverová aplikace naslouchá a kde vyřídí náš požadavek o instanci již vtvořeného objektu.

Pokud jste došli až sem, pak nezbývá než zkompilovat knihovnu a obě aplikace. Nezapomeňte přidat do obou aplikací referenci právě na naší knihovnu, kde se nachází definice objektu RemoteObject.
Po zkompilování pusťte nejprve ServerApplication a poté ClientApplication. Střídavým přepínáním mezi aplikacemi a stiskáváním libovolné klávesy uvidíte, jak klientská aplikace komunikuje se serverovou. V případě stisku klávesy v serverové aplikaci zvýšíte hodnotu _Counter o jednu. Pokud tak učiníte několikrát za sebou a pak přepnete do klientské aplikace, tak tam se vám po stisku klávesy zobrazí skutečně aktuální hodnota proměnné objektu, který se nachází v serverové aplikaci. Konec konců sami dobře víte, že v klientské aplikaci se žádné navyšování této hodnoty neděje, tam poze tuto hodnotu čteme.

Poznámka: Je nutné povolit komunikaci programů ve Windows Firewallu, který většině z vás zobrazí dotaz na púovolení této komunikace. Pokud nezobrazí a program nebude fungovat, vězte, že za to může právě firewall a jeho nastavení

Možná že se budete muset trochu poprat s tímto příkladem, ale věřte, funguje to. Zajímavé to začne být ve chvíli, kdy ServerApplication spustíte na jiném počítači než ClientApplication. V takovém případě bude zjevné, že skutečně dochází ke vzdálené komunikaci mezi oběma aplikacemi. V tom případě neopomeňte opravit url cestu k objektu.

.NET Remoting je opravdu velmi silný nástroj a pokud se vám zdá, že byste pro tuto technologii našli uplatnění ve vašich projektech, doporučuji hlubší studium. Nastudujte si termíny jako je  Singleton, Singlecall, SOAP a pod. Uvidíte, že se vám to vyplatí.

P.S: Závěrem bych chtěl poděkovat chlápkovi s loginem vlko který mě upozornil na ten skvělý Add-In díky kterému se dají zdrojové kódy kopírovat z Visual Studia v tak pěkné formě Yes

 

 

 

 

Posted: 6. února 2007 1:57 by MirekE
Vedeno pod:

Komentář

PetrVo napsal:

Pěkný článek, pro začátečníky jak dělaný.Mohl bys prosím Tě dát link na ten AddIn pro kopírování zdrojáků z VS s formátováním?

Díky

Petr

# února 6, 2007 12:30

MirekE napsal:

# února 6, 2007 12:32

pazu napsal:

Postřeh o co se dá zakopnout:

Pokud použijete na serveru konfiguraci pomocí .config souboru (což umožňuje měnit nastavení bez rekompilace progamu a není až tak od věci, krom toho serverová strana je pak jednodušší v kódu), narazí začtečník (i já narazil) na jednu podivnost - jeho kód nikde nevytváří "tu instanci toho RemoteObject". Co teď ? Rozumné řešení - pomocí statických polí inicializovat odkazy na vnější svět, odkud instane čerpá informace. Další možnost je, že třída obsahuje všechnu funkcionalitu sama, ale to není tak častý případ.

Pokud někdo znaá další možnost - napište, jsem zvědav !

Ještě drobnost pro klienta, která někdy pomůže: instanci RemoteObject lze inicializovat a použít i jako normální objekt v aplikaci. V některých applikacích pak můžete mít alternativní použití buď všechno ve vlastním procesu, nebo jet proti vzdálné mašině - a to vše pouze změnou v .config souboru.

# února 6, 2007 18:03

pavel.b napsal:

2Pazu: zkus to takto...

protected override void OnStart(string[] args)

       {

           try

           {

               //vytvoreni singletonu a aktivace remotingu

               RemotingConfiguration.Configure(

                   Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ey36svc.exe.config"),

                   false

               );

               //ziskani odkazu na objekt singletonu

               WellKnownServiceTypeEntry[] entries =

                   RemotingConfiguration.GetRegisteredWellKnownServiceTypes();

               //Ziskani objektu singletonu.

               driverObject = Activator.GetObject(

                   entries[0].ObjectType,

                   GetUrl(entries[0].ObjectUri)) as EY36Driver;

               //Start driveru.

               if (driverObject != null)

               {

                   driverObject.Start();

               }

           }

           catch (Exception RemotingEx)

           {

               evntLog.WriteEntry(RemotingEx.ToString(), EventLogEntryType.Error);

           }

       }

private string GetUrl(string uri)

       {

           //prochazeni vsech registrovanych kanalu

           foreach (IChannel iterChannel in ChannelServices.RegisteredChannels)

           {

               IChannelReceiver recChannel = iterChannel as IChannelReceiver;

               if (recChannel != null)

               {

                   string[] urls = recChannel.GetUrlsForUri(uri);

                   return urls[0];

               }

           }

           return string.Empty;

       }

# února 7, 2007 0:28

jan.barnet napsal:

Pro začátečníka se to možná ukázkově hodí, ale mně se jako největší průser tohoto řešení zdá být to, že knihovnu s RemoteObject je poté potřeba rozdistribuovávat při každé změně RemoteObject jak na serveru tak na všechny klienty.

# listopadu 4, 2009 19:26
Neregistrovaní uživatele nemužou přidávat komentáře.
Vyvojar.cz na prodej!