Co to jest.net Remoting? Technologia dedykowana do komunikacji między różnymi domenami aplikacji może ona zachodzić w ramach tego samego procesu, między procesami na pojedynczym systemie między procesami na różnych systemach gdzie po obu stronach jest aplikacja.net
Inne technologie do komunikacji między klientem a serwerem Gniazda sieciowe Klasy z System.Net Usługi sieciowe (luźne połączenie, niezależność od platformy) WCF (Windows Communication Foundation) niezależność od platformy, szybka binarna komunikacja między aplikacjami.net
Ogólna architektura.net Remoting Client Hello() Transpa -rent proxy Invokes() Proxy Real proxy Remote object Hello() Process Message() Object-context sink envoy sink Process Message() Deserialize() Serialize() Formatter Channel Server-context sink Process Message() Channel Formatter Application Domain A Application Domain B
Remoting.NET założenia (1) Elastyczna architektura możliwość podmiany komponentów na własne Kanały komunikacyjne Formatery Rzeczywisty proksy Dodać własne sink objects Uproszczenie projektowania aplikacji klienckich i aplikacji serwerów Zamiast skupiać się na pisaniu serwera i całą jego otoczką programista może zająć się implementacją czystej funkcjonalności
Remoting.NET założenia (2) Proces budowania aplikacji jest praktycznie jednokrokowy Konfiguracja Remotingu może być wyniesiona poza kod umieszczana jest w pliku konfiguracyjnym XML Ewentualne zmiany adresu zdalnego komputera, czy to metody dostępu do niego nie wymagają ponownej kompilacji
Remoting.NET założenia (3) W zależności od zdefiniowanego typu klasy zdalnej serwer może zwrócić : obiekt klasy, która jest serializowalna, np. string czy DataSet Klasa taka musi posiadać atrybut [Serializable] referencje do obiektu klasy zdalnej CLR Object Remoting główna różnica w stosunku do XML Web Services (konstruktory, delegaty, interfejsy, metody, właściwości, pola,.. mogą być używane z obiektami zdalnymi a w przypadku usług ich obiekty są abstrakcyjne)
Remoting.NET założenia (4) Komunikacja pomiędzy hostem i klientem odbywa się przez kanały komunikacyjne: HTTP dla formatera XML korzysta z SOAP System.Runtime.Remoting.Channels.Http HttpClientChannel / HttpServerChannel TCP dla binarnych danych, jest szybszy może przesyłać natywne dane bez opakowywania w żadne wiadomości (kanał TCP chroniony -.NET framework 2.0) System.Runtime.Remoting.Channels.Tcp TcpClientChannel / TcpServerChannel IPC - najszybszy do komunikacji w ramach tego samego systemu między różnymi procesami - wykorzystuje windows owy mechanizm komunikacji między procesami (.NET framework 2.0)
Remoting.NET założenia (5) Obiekty zdalne są formatowane albo binarnie, albo w formacie SOAP XML System.Runtime.Serialization.Formatters.Binary.BinaryFormatter System.Runtime.Serialization.Formatters.Soap.SoapFormatter - wsparcie jedynie dla stylu SOAP RPC (w nowej wersji SOAP styl RPC jest niezalecany) Kanały HTTP i TCP mogą mieć formater binarny lub SOAP Formater provider wykorzystywany do stowarzyszenia formatera z kanałem komunikacyjnym
Remoting.NET założenia (6) Typy aktywacji obiektów zdalnych SERVER-ACTIVATED OBJECTS: SingleCall nowa instancja obiektu jest tworzona dla każdego nowego klienta i dla każdego wołania Singleton tylko jedna instancja obiektu do obsługi wszystkich klientów i ich wołań CLIENT-ACTIVATED OBJECTS dla każdego klienta tworzona nowa instancja obiektu ale ta sama dla jego kolejnych wołań
Scenariusz tworzenia aplikacji 1. Stworzenie tzw. RemotableType (.dll) 2. Uruchomienie aplikacji hosta zarejestrowanie klasy zdalnej utworzenie i zarejestrowanie kanału serwera do komunikacji 3. Uruchomienie aplikacji klienckiej utworzenie i zarejestrowanie kanału klienta do komunikacji zarejestrowanie klasy zdalnej w lokalnej domenie stworzenie zdalnego obiektu (referencja lokalna) utworzenie proxy operowanie na proxy jak na obiekcie lokalnym
Wołanie typu Server-activated - tryb aktywacji SingleCall client application domain server application domain Klient Klient Ob_zdalny x = new Ob_zdalny(); int a = x.metoda1(); int a = x.metoda1(); Proxy Proxy Formater Obiekt Marshal-by-reference object Formater instancja obiektu instancja zdalnego obiektu zdalnego instancja obiektu zdalnego dla Klienta2 Kanał Kanał transportowy Kanał transportowy
Wołanie typu Server-activated - tryb aktywacji Singleton client application domain server application domain Klient Klient Ob_zdalny x = new Ob_zdalny(); Proxy Proxy Obiekt Marshal-by-reference object instancja obiektu zdalnego wspólna dla wszystkich int a = x.metoda1(); int a = x.metoda1(); Formater Formater Formater Kanał Kanał transportowy transportowy Kanał transportowy
Wołanie typu Server-activated - tryb aktywacji Singleton(2) Wołania metod obiektu zdalnego nie są synchronizowane przez.net Framework Jeżeli 2 klientów woła metodę obiektu zdalnego dokładnie w tym samym momencie to wołania te dojdą w 2 różnych wątkach i będą wykonane współbieżnie. Aby zabezpieczyć się przed taka możliwością należy zaimplementować obiekt zdalny w trybie thread-safe
Wołanie typu Client-activated client application domain Klient Klient (k1) Proxy Proxy server application domain Obiekt Marshal-by-reference object instancja obiektu zdalnego dla k1 Ob_zdalny x = new Ob_zdalny(); int a = x.metoda1(); int a = x.metoda1(); Formater Formater instancja obiektu zdalnego dla Klienta2 Kanał Kanał transportowy Kanał transportowy
Stworzenie RemotableType (1) Dla zdalenego wołania można zdefiniować 3 typy klas: Marshal-by-reference (dziedziczy po klasie MarshalByRefObject) można go zserializować przez referencje, tzn. obiekt nie jest przekazywany przez sieć, ale zwracany jest jego proksy Marshal-by-value (domyślne w.net) obiekt serializowany przez wartość cały obiekt przesyłany przez kanał, musi być oznaczony atrybutem [Serializable], obiekt zserializowany dla klienta jest niezależyny od obiektu na serwerze) Nonremotable klasy nie serializowane i nie dziedziczące z MarshalByRefObject związane z domeną aplikacyjną, w której zostały stworzone csc /noconfig /t:library RemotableType.cs ( kompilacja klasy lub utwórzyć projekt w Visual Studio.NET i wybrać Class Library) Tak zbudowaną bibliotekę podłączymy pod hosta i do klienta ponieważ.net Framework wymaga metadanych opisujących zdalną klasę przy tworzeniu proxy po stronie klienta
Stworzenie RemotableType (2) using System; public class RemotableType : MarshalByRefObject { private string wiadomosc = Test RemotableType."; public string getwiadomosc(){ return wiadomosc; } }
Stworzenie aplikacji hosta (1) przykład singleton using System; using System.Runtime.Remoting; public class Listener { public static void Main(){ } Wczytujemy konfiguracje z pliku xml RemotingConfiguration.Configure("Listener.exe.config"); Console.WriteLine( Czekam..."); Console.ReadLine(); } Skompilować podając bibliotekę: csc /noconfig /r:remotabletype.dll Listener.cs (lub utwórz projekt aplikacji i dodaj referencje do biblioteki)
Assembly name Stworzenie aplikacji hosta (2) przykład singleton <configuration> <system.runtime.remoting> <application> <service> <wellknown mode="singleton" type="remotabletype, RemotableType" objecturi="remtype" /> </service> <channels> <channel ref="http" port="8989"/> </channels> </application> </system.runtime.remoting> </configuration> Zawartość pliku konfiguracyjnego xml dla hosta - Listener.exe.config namespace Remote object name
Tworzenie aplikacji klienta (1) dla wołania typu singleton using System; using System.Runtime.Remoting; public class Client{ public static void Main(){ RemotingConfiguration.Configure("Client.exe.config"); RemotableType remoteobject = new RemotableType(); Console.WriteLine(remoteObject.getWiadomosc()); } } Kompilujemy też podając bibliotekę: csc /noconfig /r:remotabletype.dll Client.cs (lub utwórz projekt i aplikacji i dodaj referencje do biblioteki)
Tworzenie aplikacji klienta (2) dla wołania typu singleton <configuration> <system.runtime.remoting> <application> <client> Zawartość pliku konfiguracyjnego xml dla klienta - Client.exe.config <wellknown type="remotabletype, RemotableType" url="http://localhost:8989/remtype" /> </client> </application> </system.runtime.remoting> </configuration>
Wywołanie typu Singleton
Konfigurowanie Remotingu z poziomu kodu Host (tryb singlecall) Dodanie kanału typu TCP ChannelServices.RegisterChannel(new Tcp.TcpChannel(1234)); Dodanie klasy RemoteType, aktywacja za każdym razem RemotingConfiguration.RegisterWellKnownServiceType(GetType(Remot etype), RemType, WellKnownObjectMode.SingleCall); klasa zdalna URI dla klasy zdalnej tryb aktywacji można stosować, choć zmniejsza elastyczność całego rozwiązania
Konfigurowanie Remotingu z poziomu kodu Klient (tryb singlecall) Dodanie kanału typu TCP ChannelServices.RegisterChannel(new Tcp.TcpChannel(1234)); Zarejestrowanie klasy RemoteType RemotingConfiguration.RegisterWellKnownClientType( typeof(remotetype),"tcp://localhost:1234/ RemType "); klasa zdalna URL dla klasy zdalnej można stosować, choć zmniejsza elastyczność całego rozwiązania
Wywołanie typu SingleCall
Konfigurowanie Remotingu z poziomu Host Client-Activated Rejestracja kanału: TcpServerChannel kanal3 = new TcpServerChannel (1236); ChannelServices.RegisterChannel (kanal3); Rejestracja klasy zdalnej: RemotingConfiguration.RegisterActivatedServiceType( typeof(stoper));
Konfigurowanie Remotingu z poziomu Klient Client-Activated Rejestracja kanału: TcpClientChannel kanal2 = new TcpClientChannel(); ChannelServices.RegisterChannel(kanal2); Rejestracja klasy zdalnej w lokalnej domenie: RemotingConfiguration.RegisterActivatedClientType( typeof(stoper),"tcp://localhost:1236");
Klasa System.Activator - tworzenie instancji obiektu zdalnego Metoda GetObject dla server-activaded objects RemoteType R_object = (RemoteType) Activator.GetObject(typeof(RemoteType),"tcp://localhost:1234/ RemoteType ); Metoda CreateInstance dla client-activated objects object[] url = { new UrlAttribute ( tcp://localhost:1234 ) }; Stopwatch sw = (Stopwatch) Activator.CreateInstance(typeof(Stopwatch), null, url); Metody te stosujemy zamiennie za rejestracje klasy po stronie klienta i powoływanie obiektu przez new. Przydatne jeśli klasa zdalna implementuje interfejs i nic więcej poza adresem URL i typem interfejsu o niej nie wiemy (przez new nie da się jej wywołać).
Czas życia obiektów zdalnych(1) Jeżeli klient woła metodę obiektu zdalnego i nie może się do niego dostać generowany jest wyjątek System.Runtime.Remoting.RemotingException, który należy obsłużyć Jak serwer rozpoznaje, że klient nie jest już zainteresowany obiektem i kiedy można obiekt usunąć? Leasing Distributed Garbage Collector (LDGC) do zarządzania czasem życia obiektów
Czas życia obiektów zdalnych(2) SingleCall (dla każdego żądania nowy obiekt) obiekt żyje dokładnie w czasie wołania metody, potem jest oznaczany do usunięcia przez garbage collector Czas życia kontrolowany przez obiekt dzierżawcy implementujący ILease z System.Runtime.Remoting.Lifetime, definiujący czas dzierżawy(leasetime=300sek) Singleton Client-activated jeżeli czas ten upłynie obiekt jest rozłączany i oznaczany do usunięcia jeżeli po tym czasie klient wyśle żądanie metody to wygenerowany będzie wyjątek
Czas życia obiektów zdalnych(3) Odnawianie dzierżawy przez: ukryte wznowienie automatycznie wykonywane przy wołaniu metody przez klienta jeżeli bieżący czas dzierżawy jest mniejszy od wartości parametru RenewOnCallTime to jest mu przypisywana wartość RenewOnCallTime. wyraźne wznowienie klient może określić nowy czas dzierżawy; wykorzystanie metody Renew() interfejsu ILease wznowienie sponsorowane klient może utworzyć sponsora implementującego interfejs ISponsor i zarejestrować go w usługach dzierżawcy metodą Register() interfejsu ILease. Sponsor definiuje czas przedłużania dzierżawy. Gdy czas życia obiektu dobiega końca serwer zapytuje sponsora czy przedłużyć go.
Czas życia obiektów zdalnych(4) (ILease Properties :) InitialLeaseTime (get, set) długość czasu życia obiektu (300s) RenewOnCallTime (get, set) minimalna wartość na którą jest ustawiany LT za każdym razem gdy obiekt zdalny odbiera wołanie metody (120 sek) SponsorshipTimeout (get,set) czas oczekiwania na odpowiedź od sponsora (na ile ustawia LT), po tym czasie szukany do odpytania kolejny sponsor (120 sek) LeaseManagerPollTime (10 sek) przedział czasu przez który zarządca dzierżawy powstrzymuje się przed wygaśnięciem obiektu CurrentLeaseTime (get)- ilość czasu pozostająca do momentu dezaktywacji obiektu jeżeli nie odebrał on wołania metody
Przykład W serwerze wymuszamy tryb client-activated object RemotingConfiguration.ApplicationName = "Hello"; RemotingConfiguration.RegisterActivatedServiceType(typeof(Hello)); W kliencie tryb tworzenia obiektu: ChannelServices.RegisterChannel(new TcpClientChannel(), true); object[] attrs = {new UrlAttribute("tcp://localhost:8086/Hello") }; //namespace System.Runtime.Remoting.Activation Hello obj = (Hello)Activator.CreateInstance(typeof(Hello), null, attrs); Aby pokazać jaki mamy czas dzierżawy wykorzystamy metodę GetLifetimeService() przeźroczystego proksy ILease lease = (ILease)obj.GetLifetimeService(); //namespace System.Runtime.Remoting.Lifetime if (lease!= null) { Console.WriteLine("Lease Configuration:"); Console.WriteLine("InitialLeaseTime: " + lease.initialleasetime); Console.WriteLine("RenewOnCallTime: " + lease.renewoncalltime); Console.WriteLine("SponsorshipTimeout: " + lease.sponsorshiptimeout); Console.WriteLine(lease.CurrentLeaseTime); }
Przykład cd. Zmiana konfiguracji dzierżawy obiektu zdalnego na serwerze: (namespace System.Runtime.Remoting.Lifetime) LifetimeServices.LeaseTime = TimeSpan.FromMinutes(10); LifetimeServices.RenewOnCallTime = TimeSpan.FromMinutes(2); Ustawienie specyficznych czasów dzierżawy w samej definicji klasy obiektu zdalnego public class Hello : System.MarshalByRefObject { public Hello() { Console.WriteLine("Constructor called"); } public override Object InitializeLifetimeService() { ILease lease = (ILease)base.InitializeLifetimeService(); lease.initialleasetime = TimeSpan.FromMinutes(10); lease.renewoncalltime = TimeSpan.FromSeconds(40); return lease; } }
Bezpieczeństwo W.NET 1.1 tylko jeśli zdalny obiekt udostępniany przez IIS i ASP.NET W.NET 2.0 wparcie dla poufności przesyłanych danych i uwierzytelniania użytkownika konfigurowalne z dowolnym kanałem; w konfiguracji po stronie serwera definiujemy minimalne wymagania na bezpieczeństwo, po stronie klienta jego zdolność do zapewnienia bezpieczeństwa Jeżeli klient nie jest w stanie spełnić minimalnych wymagań serwera to nie ma komunikacji
Bezpieczeństwo - przykład Konfiguracja serwera <channels> <channel ref="tcp" port="9001" secure="true" protectionlevel="encryptandsign" impersonate="false" /> </channels> Konfiguracja klienta <channels> <channel ref="tcp" secure="true" protectionlevel="encryptandsign" TokenImpersonationLevel="Impersonate" /> </channels> Anonymous / Identyfication / Impersonation/ Delegation Czy serwer wymaga kodowania przesyłanych danych? None / Sign /EncryptAndSign Jeżeli True - serwer uzyskuje dostęp do zasobu w imieniu klienta
Bezpieczeństwo- cd. Jeżeli kanał tworzony programowo Dictionary<string, string> dict; = new Dictionary<string, string>(); dict.add("secure", "true"); TcpClientChannel clientchannel = new TcpClientChannel(dict, null);
Porównanie technologii RPC cecha RMI Remoting Format wymiany JRMP/IIOP XML/TCP Dostęp do obiektu Rejestr RMI Activator Protokoły Sposoby przekazywania parametrów Możliwości tworzenia własnych kanałów TCP wartość/referencje Socket Factories TCP/HTTP wartość/referencje Własne kanały
Porównanie wydajności RMI vs Remoting Java RMI and.net Remoting Performance Comparison Willem Elbers, Frank Koopmans and Ken Madlener Radboud Universiteit Nijmegen December 2004