Windows NT für Programmierer

Kapitel 10: Objektkommunikation mit COM und DCOM

Überblick

Letzte Änderung: 28.9.98 von B. Tritsch

Zurück zum Inhalt


Verteilte Applikationen

Die Basisidee einer verteilten Umgebung ist die Entwicklung von Anwendungen und Diensten nach dem Komponentenprinzip. Dies resultiert aus einem Aufbrechen der bisher monolithisch angelegten Anwendungen, die schwer wartbar und schlecht auf die Mitglieder von Entwicklergruppen aufzuteilen sind. Die Aufteilung der Applikationsmonolithen resultiert in kleinen, eigenständigen, wiederverwendbaren und in sich abgeschlossenen Einheiten. Ermöglicht wird diese Vorgehensweise durch die Verwendung des Component Object Models (COM). Mit seiner Hilfe ist es möglich, binäre Software-Komponenten zu erstellen und die Kommunikation zwischen mehreren dieser Komponenten zu vereinheitlichen. Man kann solch eine Applikation durch Wiederverwendung bestimmter Komponenten nach dem Baukastenprinzip zusammenstellen.

Abbildung 10.1: Die beiden gängigen Modelle zur Verteilung von Applikationen: Traditionell durch alle Systemschichten und über Middleware als Abstraktionsschicht über dem Betriebssystem.

COM-Komponenten

Eine Middleware wie COM schirmt den Entwickler von Details der Kommunikationsmechanismen ab, ermöglicht die Nutzung vertrauter Techniken und bietet ein einheitliches Application Programming Interface (API). Die Middleware bildet daher eine Abstraktionsschicht zwischen der Anwendung und dem Betriebssystem und erlaubt die Kommunikation der Module einer verteilten Anwendung.

Die COM-Komponenten werden bei ihrer Installation direkt im Betriebssystem verankert. Auf diese Weise stehen sie jeder Applikation mit definierten Schnittstellen zur Verfügung und können frei verwendet werden. Problematisch ist hierbei jedoch, daß eine Applikation unter Umständen nicht mehr funktioniert oder nur stark eingeschränkte Funktionalität besitzt, wenn die benötigten COM-Komponenten nicht auf dem System installiert sind. Weiterhin werden viele Systeme von COM-Komponenten überschwemmt, da das Entfernen einer Applikation nicht zwingend auch die mit ihr installierten COM-Komponenten entfernt. Auf diese Weise befinden sich auf einigen Systemen viele „historischen COM-Leichen".

Einer der großen Vorteile von COM ist jedoch seine Sprachunabhängigkeit bei der Entwicklung – mit einer Reihe von Hochsprachen kann COM-konforme Software erstellt werden. So existieren COM-fähige Versionen von C++, Visual Basic, Fortran, Java und anderen. COM ist schon heute weit verbreitet, es dient bereits seit Jahren als Basis für das Object Linking and Embedding (OLE) und für die ActiveX-Technologie. Wirklich neu ist die Erweiterung des Standards für die Kommunikation über Maschinengrenzen hinweg, genannt Distributed COM (DCOM). Als Konkurrenz-Middleware zu CORBA und Java-RMI macht es den Einsatz von COM in verteilten Systemen möglich, indem es für den DCOM-Entwickler transparente Basismechanismen zur Netzwerkkommunikation implementiert.

Abbildung 10.2: Die verschiedenen Aufrufmechanismen eines Clients, der über definierte Schnittstellen auf Funktionalitäten zugreift, die in einer Komponente gekapselt sind. Hierbei kann sich die Server-Komponente im selben Prozeß, auf dem selben Computer oder auf einem entfernten Computer befinden. Entsprechend wird ein direkter Aufruf, ein COM-Aufruf oder ein DCOM-Aufruf ausgeführt.

Die Hauptmerkmale von COM ist die Kommunikation der Komponenten über definierte konstante Schnittstellen (Interfaces), die auch bei unterschiedlichen Implementationen stabil bleiben. Die Erweiterung einer Schnittstelle wird durch eine strenge Versionskontrolle geregelt, wobei die Vorgängerversion niemals verändert werden darf. Jede COM-Komponente implementiert jedoch immer eine spezielle Schnittstelle – IUnknown. Wird diese aufgerufen, so antwortet die angesprochene Komponente mit einer Liste aller anderen bereitgestellten Interfaces. Zur Wahrung der Eindeutigkeit besitzt jede COM-Komponenten und jede Schnittstelle eine weltweit eindeutige, 128 Bit lange Identifikationsnummer (GUID), die bei der Entwicklung mit dem speziellen Werkzeug Uuidgen generiert werden kann.

Um die Aufruf- und Kommunikationsmechanismen von COM-Komponenten vor einem Entwickler zu verstecken, werden Platzhalterfunktionen verwendet. Ein Client ruft den Platzhalter (Proxy) wie eine Funktion der Anwendung auf. Die Platzhalterfunktion ist innerhalb einer DLL realisiert, die in Wirklichkeit einen Aufruf über Prozeßgrenzen zu einem Server-Prozeß macht. Auch die Server-Funktionalität wird dabei nicht direkt angesprochen, sondern über einen Platzhalter (Stub) realisiert. Die Kommunikation zwischen Proxy und Stub ist nicht mehr unter der Kontrolle des Entwicklers, sondern wird von standardisierten COM-Mechanismen übernommen. Diese basieren auf einer Interprozeßkommunikation mit Local Procedure Call (LPCs). Die Beschreibung einer COM-Schnittstelle ist daher für einen Entwickler eine der zentralen Aufgaben. Hierfür steht die Interface Definition Language (IDL) zur Verfügung. Diese formale Beschreibung wird mit Hilfe des MIDL-Compilers in eine binäre Form übersetzt.

Abbildung 10.3: Verwendung von Proxy und Stub zur Kommunikation zwischen Client und Server-Komponente.

Wie können jedoch von einer Applikation benötigte COM-Komponenten auf dem System gefunden werden? Die Lösung für diese Frage liegt in der Registry. Dort sind alle COM-Objekte im Hive HKEY_CLASSES_ROOT registriert und können über ihre Identifikation (CLSID) angefordert werden.

Der Lieferumfang der Microsoft Visual C++ Entwicklungsumgebung und des Windows NT Resource Kits beinhaltet ein interessantes Werkzeug zum Betrachten aller installierten COM-Komponenten auf einem lokalen Computer. Das Programm OleView zeigt das Interface einer ausgewählten Komponente im Detail und hilft so Administratoren und Entwicklern bei der Kontrolle ihrer Systeme.

Abbildung 10.4: OleView bei Analysieren von COM-Komponenten.

Distributed COM - DCOM

DCOM (Distributed Component Object Model) ist ein Mechanismus, der es ermöglicht, über mehrere Computer in einem Netzwerk verteilte Anwendungen auszuführen. Eine verteilte Anwendung besteht aus mehreren Prozessen, die zusammenarbeiten, um eine Aufgabe auszuführen. Diese Prozesse können auf einem oder mehreren Computern ausgeführt werden. Hierdurch wird das Netzwerk als Ressource verwendet, um Applikationen möglichst optimal zu verteilen.

Verteilte Systeme bestehen aus autonomen und kooperierenden Prozessen, wobei diese mit Nachrichten über ein Netzwerk kommunizieren. Ein verteiltes System besitzt dabei keinen gemeinsamen physikalischen Speicher. Hierdurch kann ein solches System dynamisch auf einen Rechnerausfall, auf Erweiterungen und auf die Rekonfiguration reagieren. Weiterhin kann im Bezug auf die Netzwerkknoten (d.h. die beteiligten Computer) eine heterogene Infrastruktur eingesetzt werden.

Die Komplexität eines verteilten Systems darf bei der Planung nicht unterschätzt werden. Die Laufzeiten der Nachrichten im Netzwerk, die Reaktionszeiten der Netzwerkknoten, die Erkennung von Netzwerk- und Computer-Ausfällen, die Lokalisierung von Diensten, die Lastverteilung sowie die Definition und Pflege von Schnittstellen spielen hierbei eine wesentliche Rolle. Zumeist fehlen adäquate Werkzeuge, um die genannten Probleme zufriedenstellend zu lösen.

Abbildung 10.5: Das Modell der COM- und DCOM-Kommunikation in einer verteilten Umgebung.

DCOM nutzt als Middleware im Grunde die gleichen Konzepte wie COM, jedoch nicht nur für die lokale Kommunikation von Prozessen (Local Procedure Calls - LPCs), sondern über Computer-Grenzen hinaus (Remote Procedure Calls – RPCs). Für den Entwickler wird die Netzwerkfunktionalität über den Einsatz von entsprechenden Proxy- und Stub-DLLs versteckt.

Die COM/DCOM Middleware ist neben Windows NT und Windows 95/98 auch für Nicht-Windows-Plattformen verfügbar. Seit der Portierung der DCOM-Technologie durch die Darmstädter Software AG auf Sun Solaris, HP-UX, MVS und andere Betriebssysteme ist durch das Produkt EntireX der Nachteil der proprietären Realisierung nicht mehr gegeben.

Das Dienstprogramm Dcomcnfg zur DCOM-Konfiguration kann zur Konfiguration von 32-Bit-COM- und -DCOM-Anwendungen eingesetzt werden. Im Hauptfenster von Dcomcnfg können DCOM-Anwendung zur Konfiguration und zur Vergabe von verschiedenen Sicherheitsstufen ausgewählt werden.

Abbildung 10.6: Anwendungseigenschaften im Programm Dcomcnfg.

Bei den Standardeigenschaften von DCOM-Anwendungen lassen sich Optionen besonders konfigurieren: Die Standardstufen zur Authentifikation und zur Impersonation.

Die Stufe zur Authentifikation legt die Sicherheit für Pakete bei der Kommunikation zwischen Anwendungen fest, wobei es folgende Einstellungen gibt (von der niedrigsten zur höchsten Sicherheitsebene):

Die Stufe der Impersonation legt die Berechtigung fest, die eine Client-Anwendung einer Server-Anwendung für die Bearbeitung von Tasks für die Client-Anwendung zuweist, wobei es folgende Einstellungen gibt (von der niedrigsten zur höchsten Sicherheitsebene):

Abbildung 10.7: Standardeigenschaften der DCOM-Anwendungen.

Nicht zuletzt können global für DCOM-Anwendungen verschiedene Sicherheitsoptionen eingestellt werden. Diese betreffen die Zugriffsberechtigungen der Benutzer, die Berechtigung zum Start der Anwendungen und die Berechtigung zur Änderung OLE-Klassenkonfigurationen.

Abbildung 10.8: Einstellung der Sicherheitsoptionen für DCOM-Anwendungen.

Erzeugung von GUIDs

Die Kommunikation über COM/DCOM wird durch RPCs abgehandelt. Der Programmaufruf einer Prozedur über RPCs basiert dabei auf sogenannten Proxies, die den betreffenden Aufruf zunächst einmal lokal entgegennehmen. Aus Programmierersicht ist das so, als würde man eine Funktion aus einer lokalen Bibliothek aufrufen. Der Proxy reicht die Funktion einschließlich ihrer Parameter über das Netz an eine entfernte Plattform mit einem spezifischen Zielprozeß weiter. Dieser besitzt wiederum einen Stub, der die Funktion entgegennimmt und dem Zielprozeß in einer Weise weiterreicht, als wäre sie lokal generiert worden. Die Programmiertechnik für die Client- und Server-Komponenten ist daher nicht wesentlich unterschiedlich zur konventionellen Programmentwicklung. Die RPC-Komponenten versuchen sämtliche benötigten Netzwerkmechanismen vor dem Entwickler zu verbergen, sie ihm aber dennoch vollständig zur Verfügung zu stellen.

Um nun ein einfaches Client/Server-System mit Hilfe von RPCs zu erzeugen, sind vier Quelldateien nötig:

Mit den Dateien RPCNET.IDL und RPCNET.ACL wird der Microsoft IDL Compiler (MIDL) veranlaßt, Client- und Server-Stubs zu erzeugen. Das Ergebnis sind zwei C-Dateien (RPCNET_C.C für den Client sowie RPCNET_S.C für den Server) und eine gemeinsame Header-Datei RPCNET.H, die die C-Prototypen für gemeinsame Datenstrukturen und Remote-Aufrufe enthält.

Zur Erzeugung einer GUID bzw. einer neuen COM/DCOM-Schnittstelle verwendet man das Programm UUIDGEN.EXE, das z.B. in der Entwicklungsumgebung des Microsoft Visual C++-Compilers enthalten ist. UUIDGEN erzeugt die GUID durch die Verwendung der aktuellen Uhrzeit und von bestimmten Netzwerkadreßinformationen.

Der Aufruf der Zeile

uuidgen -i -orpcnet.idl

aus der Kommandozeile („DOS-Box") führt zur Erzeugung der Datei RPCNET.IDL mit folgendem Inhalt:

[
uuid(a7f70df0-836a-11d0-9281-0000c072920b),
version(1.0)
]
interface INTERFACENAME
{
}

Uuidgen.gif (7753 bytes)

Abbildung 10.9: Bildschirmschnappschuß bei verschiedenen Aufrufen von UUIDGEN.EXE aus der NT-Shell.

Dies ist auch schon die Ausgangsbasis für die weiter oben aufgeführte Datei RPCNET.IDL. Mit einem ASCII-Editor oder mit dem Developer Studio kann nun RPCNET.IDL erweitert werden. Die Erweiterungen umfassen den gewählten Namen der Schnittstelle (Rpcnet) und die verwendete Remote-Funktion. Die [in]- bzw. [out]-Parameterattribute sind bei der Funktionsdeklaration nötig, um dem MIDL-Compiler mitzuteilen, in welche Richtung die Daten über das Netz geschickt werden sollen:

[in]: Ein Wert wird zur Remote-Prozedur übergeben, wenn sie vom Client aufgerufen wird.

[out]: Ein Wert wird vom Server zur aufrufenden Prozedur auf dem Client zurückgeschickt, wenn die Remote-Prozedur abgearbeitet wurde. Ein out-Parameter muß ein Pointer oder ein Array sein, damit er über eine Referenz zum Client-Stub gelangen kann.

Zum nächsten Kapitel