Middleware-Konzepte Entfernte Aufrufe
Middleware-Konzepte Entfernte Aufrufe
Middleware-Konzepte Entfernte Aufrufe
Erfolgreiche ePaper selbst erstellen
Machen Sie aus Ihren PDF Publikationen ein blätterbares Flipbook mit unserer einzigartigen Google optimierten e-Paper Software.
<strong>Middleware</strong>-<strong>Konzepte</strong><br />
<strong>Entfernte</strong> <strong>Aufrufe</strong><br />
Dr. Gero Mühl<br />
Kommunikations- und Betriebssysteme<br />
Fakultät für Elektrotechnik und Informatik<br />
Technische Universität Berlin
Übersicht<br />
> Remote Procedure Call (RPC)<br />
> Remote Method Invocation (RMI)<br />
> Common Request Broker Architecture (CORBA)<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 2
Remote Procedure Call (RPC)
Remote Procedure Call (RPC)<br />
> Aufruf einer nicht-lokalen Prozedur entfernter Aufruf<br />
> Transparent für aufrufende und aufgerufene Prozedur<br />
> Wirkt für <strong>Aufrufe</strong>nden wie ein lokaler Aufruf Blockierung<br />
> Bekanntes, bewährtes und bequemes<br />
Programmierparadigma<br />
> Verbirgt Verteilung und Netzkomplexität<br />
> Kein händisches Festlegen von Nachrichtentypen und -inhalt<br />
> Kein händisches Verpacken/Auspacken der Parameter<br />
> Kein händischen Senden/Empfangen von Nachrichten<br />
> …<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 4
Lokaler Prozeduraufruf<br />
<strong>Aufrufe</strong>nde Prozedur<br />
Aufgerufene Prozedur<br />
P(x,y,z)<br />
1<br />
2<br />
P(a,b,c)<br />
4<br />
3<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 5
Lokaler Prozeduraufruf<br />
> Prozedur<br />
> ist eine Menge von Instruktionen mit eindeutigem Namen<br />
> besteht aus Prozedurkopf und Prozedurrumpf<br />
> definiert lokale Variablen<br />
> ist gedächtnislos<br />
> kennt den <strong>Aufrufe</strong>nden nicht<br />
> Prozeduraufruf<br />
> ist Sprunganweisung mit Prozedurnamen und Prozedurparametern (In/Out)<br />
> alternativ zu Ausgabeparametern Rückgabe eines Wertes durch<br />
return-Anweisung<br />
> aufrufende Prozedur wird blockiert, bis aufgerufene Prozedur returniert<br />
> <strong>Aufrufe</strong>nde und aufgerufene Prozedur laufen in einem Adressraum<br />
⇒ Datenaustausch über globale Variablen ist möglich und kann<br />
(unerwünschte) Seiteneffekte verursachen (möglichst) vermeiden<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 6
Prozedurparameter<br />
> Verschiedene Übergabearten möglich<br />
> call-by value, call-by reference, call-by copy/restore<br />
> Prozedurdefinition enthält die formalen Parameter<br />
> Namen, Typen, Übergabeart<br />
> Beim Aufruf werden die tatsächlichen Parameter übergeben<br />
> Compiler prüft Typkonformität<br />
PROCEDURE quadrat ( x REAL, VAR ergebnis REAL );<br />
VAR i: INT;<br />
BEGIN<br />
i := x * x;<br />
ergebnis := i;<br />
END quadrat;<br />
by value by reference<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 7
Remote Procedure Call (RPC)<br />
> Verstecken der Kommunikation hinter lokalen Prozeduren<br />
> Stubs (Stummel) sind lokale Proxies (Stellvertreter) des<br />
<strong>Aufrufe</strong>rs/Aufgerufenen, die meist (weitgehend) automatisch<br />
generiert werden<br />
....<br />
proc( a, 29 )<br />
....<br />
Stub<br />
Netz<br />
Stub<br />
proc( x, y )<br />
....<br />
....<br />
end-proc;<br />
Client<br />
Server<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 8
Client Stub<br />
> Lokaler Proxy für die aufzurufende Prozedur<br />
> Gleiche Prozedursignatur (Prozedurname, Parameter,<br />
Übergabearten) wie die aufzurufende Prozedur<br />
> Ruft ggf. Verzeichnis, Dienstvermittler auf, um Adresse des<br />
Servers zu ermitteln (Binding)<br />
> Packt Namen der aufzurufenden Prozedur und die Parameter in<br />
Anfragepaket (= Marshalling) und sendet es an den Server<br />
> Wartet auf und empfängt Antwortpaket vom Server Stub<br />
> Entpackt Ergebnisse aus dem Antwortpaket<br />
> Gibt Ergebnisse und Kontrolle an aufrufende Prozedur zurück<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 9
Client Stub – Exemplarisches Beispiel<br />
> Signatur der aufzurufenden Prozedur<br />
double square (double x1)<br />
> Stub (gleiche Signatur)<br />
double square (double x1) {<br />
request = new_request("square");<br />
add_double(request, x1);<br />
send_request(request, server);<br />
reply = receive_reply(request);<br />
return extract_double(reply);<br />
}<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 10
Server Stub<br />
> Lokaler Proxy für die aufrufende Prozedur<br />
> Wird vom Laufzeitsystem des Servers aufgerufen<br />
> Empfängt Anfragepaket und entpackt aus ihm Namen und<br />
Parameter der aufzurufenden Prozedur (= Unmarshalling)<br />
> Ruft die jeweilige Prozedur mit den Parametern auf<br />
> Packt Ergebnisse der Prozedur in Antwortpaket und<br />
sendet es an den Client Stub<br />
> Führt evtl. Verwaltungsarbeiten aus<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 11
Server Stub – Exemplarisches Beispiel<br />
> Wird von der <strong>Middleware</strong> aufgerufen, wenn eine<br />
entsprechende Nachricht empfangen wird<br />
message square_sstub (message request) {<br />
double x1 = extract_double(request);<br />
double x2 = square(x1);<br />
reply = new_reply(request);<br />
add_double(reply, x2);<br />
return reply;<br />
}<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 12
Interface Definition Language (IDL)<br />
> Ermöglicht deklarative, Programmiersprachen-unabhängige<br />
Schnittstellendefinitionen<br />
> Eine Schnittstelle (Interface) wird beschrieben durch<br />
> Namen der aufrufbaren Operationen<br />
> Namen und Typen der Parameter der einzelnen Operationen<br />
> Zusatzinformationen, z.B. eindeutige Kennzeichnung der Definition,<br />
Art einer Operation, Verhalten bei Fehlern, ...<br />
> [in], [out], [in, out] (* für Parameter *)<br />
> [maybe] (* Attribut für Operation *)<br />
> Server-Programmierer spezifiziert Schnittstelle mit IDL<br />
> Ein programmiersprachen-abhängiger Stub Compiler erzeugt<br />
daraus Stubs für Client und Server<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 13
RPC Eigenschaften<br />
> Getrennte Adressräume machen Adressen bedeutungslos<br />
> Nachbildung von call-by-reference durch call-by-copy/restore<br />
> Aufwendig für komplexe verkettete Strukturen<br />
> Synchroner (d.h. blockierender) Aufruf<br />
⇒ Parallele Anfragen an mehrere Server nur durch<br />
Multithreading<br />
> Die aufgerufene Prozedur kann weitere RPCs aufrufen<br />
⇒ Server werden (meist) multithreaded implementiert, um<br />
zeitweise Blockierung des Servers zu vermeiden<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 14
Threads<br />
> Leichtgewichtige Prozesse<br />
> Selbstständiger Kontrollfluss mit eigenem Stack<br />
> Mehrere Threads teilen sich einen Speicherbereich<br />
> Schnellere Kontextwechsel<br />
> Einfache Kommunikation durch gemeinsamen Speicher<br />
> Kein Schutz bei Zugriff auf gemeinsamen Speicher oder<br />
gleichzeitigem Aufruf einer Prozedur durch mehrere Threads<br />
⇒ Gefahr von Inkonsistenzen<br />
⇒ Synchronisation notwendig ⇒ Deadlock-Gefahr<br />
> Multithreading ermöglicht quasi-gleichzeitige <strong>Aufrufe</strong> und<br />
Bearbeitung von RPCs<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 15
Threads: Usage<br />
> Client several concurrent invocations<br />
> Server serving several clients concurrently<br />
Parallel<br />
Execution<br />
Server 1 Server 2<br />
Server 3<br />
A call is<br />
waiting<br />
One idle<br />
thread<br />
Client 1 Client 2 Client 3 Client 4<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 16
RPC Fehlersemantik<br />
> RPC hat andere Fehlersemantik<br />
als lokaler Prozeduraufruf!<br />
> Was kann alles schief gehen<br />
Client<br />
1. Client findet den Server nicht<br />
2. Client stürzt ab, nachdem er den Auftrag abgeschickt hat<br />
3. Auftrag geht verloren<br />
4. Server stürzt ab, nachdem er den Auftrag empfangen hat,<br />
aber bevor er die Antwort abgeschickt hat<br />
5. Antwort geht verloren<br />
6. Client stürzt ab, bevor er die Antwort erhalten<br />
(und bearbeitet) hat<br />
Server<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 17
RPC Fehlersemantik<br />
> Ist ein Fehler aufgetreten<br />
> Unterscheidung zwischen langsamen und verlorenen<br />
Nachrichten bzw. zwischen langsamen und abgestürztem<br />
Client bzw. Server in verteilten Systemen nicht möglich!<br />
> Client wartet auf Antwort zu seinem Auftrag<br />
> Wann soll er den Auftrag erneut schicken<br />
> Server wartet auf Bestätigung der Antwort/neuen Auftrag<br />
> Wann soll er die Antwort erneut schicken<br />
> Wie lange soll er die Antwort aufheben<br />
> Setzen von sinnvollen Timeouts äußerst schwierig!<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 18
RPC Fehlersemantik – Client Crash<br />
> Abgestürzte Clients blockieren Ressourcen beim Server<br />
(z.B. extra für den Client erzeugte Prozesse Waisen)<br />
> Mögliche Gegenmaßnahmen<br />
> Client schickt regelmäßig Heartbeat (Wie oft)<br />
> Server fragt nach, ob Client noch existiert (Wie oft)<br />
> Verbindungslose <strong>Aufrufe</strong><br />
> Neustart des Clients: alte Antworten dürfen nicht stören<br />
> Epochen-Zähler beim Neustart inkrementieren und im<br />
persistenten Speicher ablegen<br />
> Antworten aus vergangenen Epochen werden ignoriert<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 19
Steigende<br />
Komplexität<br />
RPC Fehlersemantik – Server Crash<br />
> Beim Client tritt Timeout beim Warten auf Antwort auf<br />
> Wie oft wurde der Auftrag ausgeführt<br />
> maybe evtl. gar nicht, einmal, mehrfach<br />
(einfach implementierbar)<br />
> at least once min. einmal (Wiederholungen)<br />
> at most once max. einmal (Seriennummern)<br />
> exactly once genau einmal<br />
Server<br />
Receive<br />
Execute<br />
Reply<br />
Server<br />
Receive<br />
Execute<br />
Crash<br />
Server<br />
Receive<br />
Crash<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 20
Kann „exactly once“-Semantik erreicht werden<br />
> Szenario: Client schickt Druckauftrag an Server<br />
> Server schickt eine Bestätigung, wenn der Auftrag eintrifft<br />
> Nach einem Crash schickt der Server „Wieder da“ an alle<br />
Clients<br />
> Erfährt der Client vom Crash des Servers, kann er den<br />
Auftrag wiederholen<br />
1. niemals<br />
2. immer<br />
3. nur, wenn Bestätigung eingetroffen ist<br />
4. nur, wenn Bestätigung nicht eingetroffen ist<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 21
Kann „exactly once“-Semantik erreicht werden<br />
> Aktionen des Servers<br />
> M schicke Bestätigung<br />
> P drucke Text<br />
> C Crash<br />
> Server kann Bestätigung schicken,<br />
> M P bevor der Druckauftrag angestoßen wird<br />
> P M nachdem der Druckauftrag angestoßen wurde<br />
> Betrachte den Fall eines Server-Crashs<br />
> Eine mögliche Reihenfolge ist: M P C<br />
> Sechs Reihenfolgen insgesamt<br />
(jeweils 3 für M P bzw. P M)<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 22
Kann „exactly once“-Semantik erreicht werden<br />
> Betrachte Kombinationen der Client- und Server-<br />
Strategien – wie oft wird der Druckauftrag ausgeführt<br />
⇒ Keine Strategie-Kombination, ist stets erfolgreich<br />
Client<br />
Server<br />
Strategie M P<br />
Strategie P M<br />
Wiederholung<br />
MPC<br />
MC(P)<br />
C(MP)<br />
PMC<br />
PC(M)<br />
C(PM)<br />
immer<br />
DUP<br />
OK<br />
OK<br />
DUP<br />
DUP<br />
OK<br />
niemals<br />
OK<br />
ZERO<br />
ZERO<br />
OK<br />
OK<br />
ZERO<br />
nur wenn bestätigt<br />
DUP<br />
OK<br />
ZERO<br />
DUP<br />
OK<br />
ZERO<br />
nur wenn nicht bestätigt<br />
OK<br />
ZERO<br />
OK<br />
OK<br />
DUP<br />
OK<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 23
Asynchronous RPC<br />
> Synchronous RPC most common<br />
> Sun RPC, DCE, J2EE, CORBA, .NET etc.<br />
> Asynchronous RPC<br />
⇒ Client is not blocked while waiting for reply<br />
> Two common approaches<br />
> Callback is executed when reply arrives<br />
(⇒ results are processed in a different context!)<br />
> Client polls local proxy for reply either non-blocking or<br />
blocking (with or without timeout)<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 24
Asynchronous RPC – Examples<br />
Request<br />
Request<br />
Request<br />
local<br />
polling<br />
processing<br />
of request<br />
Ack.<br />
blocking<br />
wait<br />
Reply<br />
Reply<br />
Reply<br />
callback<br />
invoked<br />
Client<br />
Server<br />
Client<br />
Server<br />
Client<br />
Server<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 25
Multicast RPC<br />
> Mehrere Instanzen der gleichen Prozedur<br />
(z.B. auf verschiedenen Rechnern) werden mit einem<br />
einzigen Aufruf aufgerufen<br />
> Für die Verarbeitung der Resultate gibt es mehrere<br />
Möglichkeiten<br />
> Die zuerst eintreffenden Resultate werden zurückgeliefert<br />
> Die eintreffenden Resultate werden zusammengefasst<br />
(z.B. per Mehrheitsentscheidung) und ein Resultat wird<br />
zurückgegeben<br />
> …<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 26
Remote Method Invocation (RMI)
Remote Method Invocation (RMI)<br />
> Übertragung des <strong>Konzepte</strong>s des entfernten<br />
Prozeduraufrufes auf objektorientierte<br />
Programmiersprachen <strong>Entfernte</strong>r Methodenaufruf<br />
> Objekt = Zustand + Verhalten (Methoden)<br />
> Zustand alleine nützt (meist) nichts<br />
⇒ Übertragung von Objekten by value oder by copy/restore<br />
ist in heterogenen Systemen problematisch<br />
> Der Aufgerufene muss Zugriff auf die Implementierung der<br />
Methoden haben und diese auch ausführen können<br />
⇒ Häufig können Objekte daher nur per reference<br />
übergeben werden <strong>Entfernte</strong> Objektreferenz<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 28
<strong>Entfernte</strong> Objektreferenz<br />
> Identifiziert ein Objekt eindeutig in einem verteilten<br />
System<br />
> Exemplarischer Aufbau<br />
> IP-Adresse des Servers + TCP-Portnummer<br />
> Objektkennung<br />
192.168.0.1:4444:123456<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 29
Distributed Object <strong>Middleware</strong><br />
> <strong>Middleware</strong>-Plattformen basierend auf dem Konzepts des<br />
entfernten Methodenaufrufes<br />
> Beispiele<br />
> Common Object Request Broker Architecture (CORBA)<br />
> Java 2 Enterprise Edition (J2EE)<br />
> .NET<br />
> …<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 30
Common Object Request Broker Architecture<br />
(CORBA)
Object Request Broker (ORB)<br />
> "Software Bus" für verteilte Objektsysteme<br />
> Wie ein Hardware-Bus verschiedene Hardware-<br />
Komponenten verbindet, so verbindet der ORB<br />
verschiedene Software-Komponenten<br />
Object<br />
Request<br />
Broker<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 32
Objektmodell<br />
Client<br />
> Instanz einer Klasse<br />
> Hat einen Zustand<br />
> Besitzt "Namen" und Lebenszeit<br />
> Objekt<br />
> Klasse<br />
> Schablone für Objekte<br />
> Verfeinerung durch Vererbung<br />
> Polymorphe Substitution<br />
> Schnittstelle (Interface) eines Objektes<br />
> Methoden und Attribute<br />
> Kapselung der Implementierung<br />
Schnittstelle<br />
Server<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 33
Object Request Broker (ORB)<br />
> Einbettung von Objekt-Implementierungen<br />
("Server-Objekte")<br />
> Vergabe von Objektreferenzen<br />
> Entgegennehmen von <strong>Aufrufe</strong>n des Clients<br />
> Transport der <strong>Aufrufe</strong> zum Server<br />
> Ggf. Aktivierung eines Server-Objektes<br />
> Übergabe des Aufrufs an das Server-Objekt<br />
> Entgegennehmen von Ergebnissen und Transport /<br />
Rückgabe an den Client<br />
> Unterstützung von Sicherheits- und<br />
Abrechnungsfunktionen<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 34
CORBA-Schnittstellen<br />
Client<br />
Objekt-Implementierung<br />
Dynam.<br />
Aufruf<br />
IDL<br />
Stub<br />
ORB<br />
Interface<br />
Dynam.<br />
Skeleton<br />
IDL<br />
Skeleton<br />
Objekt-<br />
Adapter<br />
Interface Repository<br />
ORB-Kern<br />
Implementation Rep.<br />
standardisiert<br />
intern<br />
Anwendung<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 35
CORBA IDL<br />
Schnittstelle<br />
Client<br />
C<br />
C++<br />
Smalltalk<br />
Cobol<br />
Ada<br />
Java<br />
.....<br />
IDL<br />
Server<br />
interface Quoter {<br />
double get_quote (in string stock_name);<br />
};<br />
<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 36
Entwicklung einer Anwendung<br />
interface Quoter {<br />
.....<br />
};<br />
IDL<br />
IDL Compiler<br />
Client Stub<br />
Server Skeleton<br />
Client<br />
Server<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 37
Ablauf<br />
1. Definition der Schnittstellen in IDL<br />
2. Mittels IDL-Compiler Stubs und Skeletons generieren<br />
3. Implementierung des Klienten<br />
4. Implementierung des Servants<br />
(d.h., der Objektimplementierung)<br />
5. Implementierung des Servers<br />
6. Registrierung des Servants beim ORB<br />
7. Methodenaufrufe des Klienten auf dem Objekt<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 38
Statische <strong>Aufrufe</strong><br />
> Verwenden das Static Invocation Interface (SII)<br />
> Schnittstellen stehen zur Compile-Zeit fest<br />
> IDL-Compiler erzeugt aus den Schnittstellen die Stubs<br />
> Typüberprüfung schon zur Compile-Zeit möglich<br />
> Stub vertritt die lokal nicht vorhandenen Prozedur<br />
> Kaum Unterschiede zum lokalen Aufruf<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 39
Dynamische <strong>Aufrufe</strong><br />
> Verwenden das Dynamic Invocation Interface (DII)<br />
> DII ist unabhängig von der konkreten Schnittstelle des<br />
aufgerufenen Objekts<br />
> Vorteil: Schnittstelle muss nicht zur Compile-Zeit<br />
vorliegen, da Aufruf zur Laufzeit zusammengestellt wird<br />
> Allerdings deutlich mehr Code notwendig<br />
> Normalerweise deutlich ineffizienter, als statische <strong>Aufrufe</strong><br />
> Typüberprüfung erst zur Laufzeit möglich<br />
> Folgende Angaben sind für einen Aufruf notwendig<br />
> Objekt, Operation, Argumente (Anzahl, Typ, Modus, Wert),<br />
Rückgabetyp<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 40
Ablauf eines dynamischen Aufrufs<br />
1. Objektreferenz beschaffen (z.B. über Name Service)<br />
2. Schnittstelle bestimmen (z.B. im Interface Repository)<br />
3. Request Pseudo Object erzeugen und füllen<br />
( = Behälter für die zum Aufruf gehörenden Informationen)<br />
4. Request Pseudo Object an ORB übergeben<br />
( = Starten des Aufrufs)<br />
5. Auf Ergebnis warten (optional)<br />
6. Request Pseudo Object löschen oder wieder verwenden<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 41
Mögliche Aufrufarten mit dem SII und dem DII<br />
> Synchroner Aufruf<br />
> Client blockiert bis Antwort zurück (oder Fehler)<br />
> Aufruf- und Rückgabeparameter möglich<br />
> Möglich für statische und dynamische <strong>Aufrufe</strong><br />
> Oneway Aufruf ( = "fire and forget“ )<br />
oneway void sayGoodBye(...);<br />
> Kein Rückgabewert oder Rückgabeparameter<br />
> Keine Exceptions bei Fehlern<br />
> Semantik hängt vom ORB ab<br />
(können z.B. auch blockierend sein!)<br />
> Möglich für statische und dynamische <strong>Aufrufe</strong><br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 42
Mögliche Aufrufarten mit dem SII und dem DII<br />
> Asynchroner Aufruf (Deferred Synchronous)<br />
> Client blockiert nicht<br />
> Aufruf- und Rückgabeparameter möglich<br />
> Zustand des Request-Objekts kann abgefragt werden<br />
> Nur möglich für dynamische <strong>Aufrufe</strong><br />
> Bedarf für asynchrone <strong>Aufrufe</strong> mittels des SIIs AMI<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 43
Mögliche Aufrufarten mit dem AMI<br />
> CORBA Messaging (ab CORBA 2.3) ermöglicht asynchrone<br />
<strong>Aufrufe</strong> mit dem SII Asynchronous Method Invocation (AMI)<br />
> AMI unterstützt zwei Modelle<br />
> Callback Model<br />
> Client gibt dem Aufruf eine Objektreferenz für Antwort mit<br />
> ORB benutzt diese Objektreferenz, um Antwort abzuliefern<br />
> Client muss als Server agieren<br />
> Ergebnis wird nicht im Kontext des <strong>Aufrufe</strong>nden verarbeitet<br />
> Polling Model<br />
> Aufruf gibt sofort ein Pseudo-Objekt zurück<br />
> Client kann an diesem Objekt pollen bzw. warten<br />
> Ergebnis wird im Kontext des <strong>Aufrufe</strong>nden verarbeitet<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 44
Zusammenfassung der möglichen Aufrufarten<br />
Static Invocation<br />
Interface (SII)<br />
Dynamic Invocation<br />
Interface (DII)<br />
Asynchronous<br />
Invocation<br />
Interface (AMI)<br />
Two-Way<br />
Synchronous Call<br />
Oneway<br />
Call<br />
Deferred<br />
Synchronous Call<br />
Asynchronous<br />
Call (Callback)<br />
Asynchronous<br />
Call (Polling)<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 45
CORBA Beispiel: Stock Quote Server<br />
> Szenario: Aktienkurse sollen von einem Server an eine Menge<br />
von Clients zugestellt werden<br />
> Mehrere Implementierungen sind möglich<br />
> Pull: Der Server bietet über eine Schnittstelle die aktuellen Kurse<br />
diverser Aktien an; Clients fragen diese (periodisch) ab<br />
> Synchrone <strong>Aufrufe</strong> (SII oder DII möglich)<br />
> Asynchrone <strong>Aufrufe</strong> mit dem DII<br />
> Asynchrone <strong>Aufrufe</strong> mit AMI (Callback oder Polling Model)<br />
> Push: Clients registrieren Callbacks beim Server; dieser ruft beim<br />
Vorliegen eines neuen Kurses den Callback beim Client auf<br />
> Synchrone Aufruf (SII oder DII möglich)<br />
> Oneway-<strong>Aufrufe</strong><br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 46
1. Implementierungsmöglichkeit: Pull
CORBA Example: Stock Quote Server<br />
module Stock<br />
// CORBA IDL implemented by server developer<br />
{<br />
// Requested stock does not exist.<br />
exception Invalid_Stock {};<br />
interface Quoter {<br />
// Two-way operation to retrieve current stock value.<br />
double get_quote (in string stock_name)<br />
raises (Invalid_Stock);<br />
};<br />
}<br />
// ...<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 48
Used Classes<br />
Quoter<br />
double get_quote (<br />
in string stock_name)<br />
…<br />
IDL written by server developer<br />
Stubs generated by IDL compiler<br />
Servant implemented by server developer<br />
Stock::QuoterBOAImpl<br />
double get_quote (<br />
const char *stock_name)<br />
Quoter_var<br />
double get_quote (<br />
const char *stock_name)<br />
…<br />
Client-Side<br />
RMI<br />
MyQuoter<br />
double get_quote (<br />
const char *stock_name)<br />
Server-Side<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 49
Example: Stock Quote Server<br />
(Servant)<br />
// C++ implementation class for IDL interface.<br />
class My_Quoter<br />
// Inherits from a generated CORBA skeleton class.<br />
: virtual public Stock::QuoterBOAImpl<br />
{<br />
public:<br />
My_Quoter (Quote_Database *db): db_ (db) {}<br />
// Invoked by the CORBA skeleton.<br />
virtual double get_quote (const char *stock_name)<br />
throw (Stock::Invalid_Stock) {<br />
double value =<br />
db_->lookup_stock_price (stock_name);<br />
if (value == -1) throw Stock::Invalid_Stock();<br />
return value;<br />
}<br />
private:<br />
Quote_Database *db_;<br />
};<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 50
Example: Stock Quote Server<br />
(Server Side)<br />
// Pointer to online stock quote database.<br />
extern Quote_Database *quote_db;<br />
int main (int argc, char *argv[])<br />
{<br />
// Initialize the ORB and the BOA.<br />
CORBA::ORB_var orb = CORBA::ORB_init (argc, argv, 0);<br />
CORBA::BOA_var boa = orb->boa_init (argc, argv, 0);<br />
// Create an object implementation.<br />
My_Quoter quoter (quote_db);<br />
}<br />
// Single-threaded event loop that handles CORBA<br />
// requests by making callbacks to the user-supplied<br />
// object implementation of My_Quoter.<br />
boa->impl_is_ready ();<br />
/* NOTREACHED */<br />
return 0;<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 51
Example: Stock Quote Server<br />
(Client Side)<br />
int main (int argc, char *argv[])<br />
{<br />
CORBA::Object_var obj =<br />
orb -> string_to_object(argv[1]);<br />
Quoter_var q = Quoter::_narrow (obj);<br />
}<br />
const char *stock_name = "ACME ORB Inc.";<br />
try {<br />
double value = q -> get_quote (stock_name);<br />
return 0;<br />
} catch (Invalid_Stock &) {<br />
return 1;<br />
}<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 52
Deferred Synchronous Invocations mit dem DII<br />
void get_stock_quotes(Stock::Quoter_ptr quoter_ref)<br />
{<br />
CORBA::Request_var *requests[NUM_STOCKS];<br />
for (i = 0; i < NUM_STOCKS; i++) {<br />
requests[i] = quoter_ref -> _request ("get_quote");<br />
requests[i] -> add_in_arg () send_deferred ();<br />
}<br />
}<br />
for (i = 0; i < NUM_STOCKS; i++) {<br />
requests[i] -> get_response();<br />
quotes[i] = request->return_value ();<br />
}<br />
> Concurrent calls can be issued since calls are non-blocking<br />
> Here, the overall execution time is dominated by the longest call<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 53
Asynchronous Method Invocation<br />
> IDL compiler generates additional stubs for asynchronous<br />
calls implied IDL<br />
> One version for the polling and one for the callback model<br />
> Clients must be rewritten to use asynchronous calls<br />
> Servers does not need to be changed<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 54
Used Classes (AMI Polling Model)<br />
Quoter<br />
double get_quote (<br />
in string stock_name)<br />
AMIQuoterPoller<br />
void get_quote (<br />
long timeout,<br />
double ami_return_val)<br />
Quoter_var<br />
double get_quote (<br />
const char *stock_name)<br />
AMI_QuoterPoller* sendp_get_quote (<br />
const char *stockname)<br />
…<br />
IDL written by server developer<br />
Stub generated by IDL compiler<br />
Poller object generated by IDL compiler<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 55
CORBA: AMI Polling Model (Client)<br />
void get_stock_quotes(Stock::Quoter_ptr quoter_ref) {<br />
// C++ implemented by client developer<br />
Stock::AMI_QuoterPoller *pollers[NUM_STOCKS];<br />
// issue calls to get stock quotes from exchange<br />
for (i = 0; i < NUM_STOCKS; i++)<br />
pollers[i] =<br />
quoter_ref -> sendp_get_quote(stock_symbols[i]);<br />
// collect replies<br />
for (i = 0; i < NUM_STOCKS; i++)<br />
pollers[i] -> get_quote(MAX_TIMEOUT, quotes[i]);<br />
}<br />
> Relies on the tedious Objects-by-Value (OBV) specification<br />
> The execution time is dominated by largest request duration<br />
> Reply handled in the context of the caller<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 56
CORBA: AMI Polling Model (Poller Objects)<br />
> AMI_QuoterPoller is a valuetype generated by the IDL<br />
compiler object instances are always collocated and,<br />
therefore, calls to them are local<br />
namespace Stock {<br />
// C++ generated by IDL compiler<br />
class AMI_QuoterPoller : public Messaging::Poller {<br />
public:<br />
virtual void get_quote (<br />
long timeout,<br />
double ami_return_val);<br />
};<br />
};<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 57
CORBA: AMI Polling Model (sendp_ methods)<br />
> sendp_ methods are also generated by the IDL compiler<br />
namespace Stock {<br />
// C++ generated by IDL Compiler<br />
class Quoter : public virtual CORBA::Object<br />
{<br />
public:<br />
Stock::AMI_QuoterPoller*<br />
sendp_get_quote (const char *stockname);<br />
// ...<br />
};<br />
};<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 58
Used Classes (AMI Callback Model)<br />
Quoter<br />
double get_quote (<br />
in string stock_name)<br />
AMI_QuoterHandler<br />
void get_quote (<br />
double d)<br />
StockHandler<br />
void get_quote (<br />
double d)<br />
Quoter_var<br />
double get_quote (<br />
const char *stock_name)<br />
void sendc_get_quote(<br />
AMI_QuoterHandler_ptr,<br />
const char *stockname);<br />
…<br />
IDL written by server developer<br />
Stubs generated by IDL compiler<br />
Callback to be implemented by client developer<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 59
CORBA: AMI Callback Model (Client)<br />
void get_stock_quotes(Stock::Quoter_ptr quoter_ref) {<br />
// C++ implemented by client developer<br />
// Initialize handler servants<br />
for (i = 0; i < NUM_STOCKS; i++)<br />
handlers[i] = new Stock_Handler(i);<br />
// Initialize handler object references<br />
for (i = 0; i < NUM_STOCKS; i++)<br />
handler_ref[i] = handlers[i]->_this ();<br />
}<br />
// Issue asynchronous calls using the callback model<br />
for (i = 0; i < NUM_STOCKS; i++)<br />
quoter_ref -> sendc_get_quote<br />
(handler_ref[i], stock_symbols[i]);<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 60
CORBA: AMI Callback Model (send_c methods)<br />
namespace Stock<br />
{<br />
// C++ generated by IDL Compiler<br />
class Quoter : public virtual CORBA::Object<br />
{<br />
public:<br />
void sendc_get_quote(Stock::AMI_QuoterHandler_ptr,<br />
const char *stockname);<br />
// ...<br />
};<br />
};<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 61
CORBA: AMI Callback Model (Handler Objects)<br />
namespace POA_Stock<br />
{<br />
// C++ generated by IDL Compiler<br />
class AMI_QuoterHandler<br />
: public POA_Messaging::ReplyHandler<br />
{<br />
public:<br />
virtual void get_quote (CORBA::Double d) = 0;<br />
virtual void get_quote_excep<br />
(Stock::AMI_QuoterExceptionHolder *excep)= 0;<br />
};<br />
};<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 62
CORBA: AMI Callback Model (Client Servant)<br />
class Stock_Handler<br />
: public POA_Stock::AMI_QuoteHandler<br />
{ // C++ implemented by client developer<br />
public:<br />
Stock_Handler(const int i){ i_=i; }<br />
virtual void get_quote(CORBA::Double value)<br />
throw (CORBA::SystemException)<br />
{ quotes[i_] = value; }<br />
virtual void get_quote_excep<br />
(Stock::AMI_QuoterExceptionHolder *excep)<br />
throw (CORBA::SystemException, Stock::Invalid_Stock)<br />
{ ... }<br />
}<br />
private int i_;<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 63
2. Implementierungsmöglichkeit: Push
Callbacks using oneway Methods<br />
> Clients call the register_callback method to register a callback at<br />
the server<br />
> Server calls callback to deliver new quote<br />
> Requires clients to behave as a “server”<br />
> Using synchronous calls for callbacks would raise the problem<br />
that the server could be blocked by a “slow” client<br />
> oneway IDL keyword in interface<br />
> Indicates that no reply should be passed back to the caller<br />
> Best effort and (not guaranteed to be) non-blocking<br />
> Application must handle end-to-end reliability<br />
> Semantic depends on ORB implementation<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 65
Callbacks using One-Way Methods<br />
module Stock { // CORBA IDL<br />
...<br />
module Callback<br />
{<br />
struct Info<br />
{<br />
string stock_name; double value;<br />
};<br />
interface Handler<br />
{<br />
// Oneway method called by quote server to<br />
// deliver new quote<br />
oneway void push(in Info data);<br />
};<br />
};<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 66
Callbacks using One-Way Methods<br />
};<br />
};<br />
interface Notifying_Quoter<br />
{<br />
// Called by clients to register a callback<br />
void register_callback(in string stock_name,<br />
in Callback::Handler handler)<br />
raises (Invalid_Stock);<br />
// Called by clients to unregister a callback<br />
void unregister_callback(in string stock_name,<br />
in Callback::Handler handler)<br />
raises (Invalid_Stock);<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 67
Client‘s Callback Implementation<br />
class My_CallBack<br />
: public POA_Stock::Callback::Handler<br />
{<br />
public:<br />
// Handle callback from quoter supplier.<br />
void push (const Stock::Callback::Info& info)<br />
{<br />
double price = info.value;<br />
string stock_name = info.stock_name;<br />
...<br />
}<br />
};<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 68
Client Implementation<br />
int main (int argc, char** argv)<br />
{<br />
// Initialize the ORB and the BOA.<br />
CORBA::ORB_var orb = CORBA::ORB_init (argc, argv, 0);<br />
CORBA::BOA_var boa = orb->boa_init (argc, argv, 0);<br />
// Create a new implementation object.<br />
My_Callback* cb = new My_Callback;<br />
// Get the callback object reference.<br />
Callback::Handler_var handler = cb->_this ();<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 69
Client Implementation<br />
// Obtain a Notifying_Quoter object reference,<br />
// e.g., from the Naming or Trader service<br />
Notifying_Quoter_var quoter = // ...<br />
// Register callback with the supplier.<br />
quoter -> register_callback<br />
("ACME ORB Inc.", handler);<br />
}<br />
// Now instruct the object adapter to<br />
// wait for callbacks from the supplier.<br />
boa->impl_is_ready ();<br />
/* NOTREACHED */<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 70
Bibliography<br />
1. Object Management Group (OMG). CORBA Messaging Specification. OMG Document<br />
orbos/98-0505, May 1998.<br />
2. D. C. Schmidt and S. Vinoski. Comparing Alternative Client Distributed Programming<br />
Techniques. C++ Report, 7(4), May 1995.<br />
http://www.cs.wustl.edu/~schmidt/PDF/C++-report-col3.pdf<br />
3. D. C. Schmidt and S. Vinoski. Distributed Callbacks and Decoupled Communication in CORBA.<br />
C++ Report, 8(9), Oct. 1996.<br />
http://www.cs.wustl.edu/~schmidt/PDF/C++-report-col8.pdf<br />
4. D. Schmidt and S. Vinoski. An Introduction to CORBA Messaging. C++ Report, 10(10), Nov.<br />
1998.<br />
http://www.cs.wustl.edu/~schmidt/PDF/C++-report-col15.pdf<br />
5. D. C. Schmidt and S. Vinoski. Programming Asynchronous Method Invocations with CORBA<br />
Messaging. C++ Report, 11(2), Feb. 1999.<br />
http://www.cs.wustl.edu/~schmidt/PDF/C++-report-col16.pdf<br />
6. D. Schmidt and S. Vinoski. Time-Independent Invocation and Interoperable Routing. C++<br />
Report, 11(4), Apr. 1999.<br />
http://www.cs.wustl.edu/~schmidt/PDF/C++-report-col17.pdf<br />
7. Microsoft Corp. .NET Framework Developer's Guide: Asynchronous Programming Overview.<br />
http://msdn.microsoft.com/library/default.aspurl=/library/enus/cpguide/html/cpovrasynchronousprogrammingoverview.asp<br />
<strong>Middleware</strong>-<strong>Konzepte</strong> © Gero Mühl 71