Interprozesskommunikation in verteilten Systemen

Interprocess Communication In Distributed Systems

Andres Koch
Object Engineering GmbH
Birmensdorferstrasse 32
CH-8142 Uitikon Waldegg
Tel  +41 (0) 44 400 47 00
Fax +41 (0) 44 400 47 07
email: info@objeng.ch



Erschienen in "Offene Systeme" (1993) Band 2/ Nr. 4, November 93, S. 201-209
Springer Verlag International Heidelberg.

UNIX war eines der Betriebssysteme, welches man als Pionier und als Vorreiter der Prozessorientiertheit und der dazu notwendigen Interprozesskommunikation bezeichnen kann. Die 'Pipe' (xad ) ist jedem UNIX-Benutzer auf Shell-Ebene ein Begriff, welche sich dann bis auf die tiefe System-Call-Schicht von UNIX durchzieht (pipe()). Dieser einfache und dadurch mächtige Mechanismus war am Durchsetzungs-Erfolg von UNIX nicht ganz unschuldig. Doch um den Anforderungen von offenen und vorallem verteilten Systemen gerecht zu werden, konnte die Entwicklung auch in UNIX nicht bei der Pipe halt machen. Vorallem mit UNIX V wurden neue und erweiterte Mechanismen wie die 'Message Queue', 'Shared Memory', 'Named Pipe' (FIFO) angeboten. Weitere Mechanismen wie Remote Procedure Call (RPC), Sockets, Message Passing sowie höhere Abstraktionen werden von unterschiedlichen Herstellern angeboten. Dass für offene Systeme im Bereich Interprozesskommunikation ein Standard notwendig ist, scheint offensichtlich und dieser müsste bestimmt auf OSF/DCE aufgebaut sein, um in Zukunft bestehen zu können. Einen Überblick und einen Einblick in dieses Gebiet bietet der nachfolgende Artikel

1 Einleitung

Die allgemeine Tendenz der heutigen Informations-Technologie in Richtung offene und verteilte Systeme scheint uns eine richtige Aufbruchstimmung zu bescheren. Client/Server als neue Applikations-Architektur ist in aller Munde und darf auch als einen guten, relativ einfachen Einstieg in verteilte Systeme gewertet werden.

Die Offenheit von Applikationen für verteilte Systeme hängt aber stark von der Gesamtarchitektur und darin von der Kommunikation ab, worüber die Applikationen zusammenarbeiten können. Die Gesamtarchitektur wird stark durch das 'Distributed Computing Environment' (DCE) von OSF (Open Software Foundation) ([9]) geprägt und es ist absehbar, dass sie sich auch wirklich als Standard in der Praxis durchsetzt.

Auf Basis 'Transport Service Provider' (vgl Abb.1) auf der Kommunikationseite liegen ebenfalls Standards vor, die verbreitet und akzeptiert sind (TCP/IP, SNA (IBM), NetBios (IBM), IPX/SPX (Novell)) (vgl.[6]).

Was aber läuft auf höherer Ebene (Data Exchange Facility), wo Programme (z.B. Client-Programm und Server-Programm) miteinander Daten austauschen müssen?.

Solange verschiedene Programme ihre Informationen über Dateien oder über eine gemeinsame Datenbank austauschen, wird ganz normal über die entsprechenden APIs (Application Programming Interface) gearbeitet. Ganz abgesehen von der eingeschränkten Durchsatzrate und der Komplexität der Synchronisation, hat dieses Verfahren spätestens seine Grenzen, wenn sich die Programme auf verschiedenen Rechner befinden.

Werden zwischen gleichzeitig laufenden Programmen (Prozesse, Tasks) Informationen ausgetauscht, so wird die Kommunikation möglichst direkt zwischen den Prozessen etabliert. Hier spricht man dann von Interprozess-Kommunikation oder kurz IPC (Interprocess Communication).

Befinden sich die kommunizierenden Prozesse auf dem gleichen Rechner können die Informationen via Speichertransfer mit Hilfe des Betriebssystems ausgetauscht werden. Sofern die Rechnergrenzen aber überschritten werden, muss auf die Kommunikations-Protokolle und -Kanäle zurückgegriffen werden, welche die Rechner verbindet.

Diese Mechanismen sollten natürlich so abstrakt sein, dass der Anwender (Programmierer) keinen Unterschied sieht, ob sich die Prozesse nun auf dem gleichen oder verschiedenen Rechner befinden.

Innerhalb einer Client/Server-Architektur ist das Kommunikations-Protokoll ziemlich starr. Der Client sendet eine Anfrage (Request) und der Server antwortet mit einer oder mehreren Antworten (Reply). Dieses Request-Reply-Schema hat auch auf die Interprozesskommunikation einen Einfluss. Es gibt einzelne IPC-Mechanismen, die für diesen Ablauf sehr geeignet sind (z.B. RPC). Dabei muss man sich aber bewusst sein, dass die Client/Server-Architektur automatisch eine hierarchische Struktur der laufenden Prozesse ergibt, nämlich Client zu Server und evtl. Server zu Superserver etc. Werden zukünftig die Peer-to-Peer-Architektur für Applikationen verwendet, dann sind nicht mehr alle IPC-Mechanismen gleichermassen geeignet. Dies soll im folgenden etwas näher erklärt werden.

Abb. 1: Interprozesskommunikation im OSI-7-Schichtenmodell

unix

2 IPC-Schichteneinteilung

Wir unterscheiden bei der Interprozesskommunikation folgende Schichten, die zusammengefasst wieder die 'Data Exchange Facility' ausmachen:

  • Local-IPC
  • Remote-IPC
  • Highlevel-IPC-Services
Abb. 2: IPC-Schichtenmodell

unix

Die Local-IPC ist prozessorgebunden und nur innerhalb ines Rechners möglich. Dazu IPC gehören praktisch alle bisherigen IPC-Mechanismen von UNIX, nämlich Pipe, Shared Memory und Message Queues. Die Kommunikation, man könnte auch von einem IPC-Adressbereich sprechen, ist nur innerhalb eines Rechnersystems unterstützt. Entsprechend dieser Einschränkung können natürlich einfachere und schnellere Schnittstellen realisiert werden. Local-IPC genügt in der Regel auch für Prozesse, die auf einem als Server dienenden Rechner laufen. Also zum Beispiel Datenbank-Server-Prozess und seine Threads (leichtgewichtige Prozesse, die auf den gleichen Adressraum wie der Prozess, dem sie zugeordnet sind, zugreifen können).

Bei der Remote-IPC, handelt es sich um Mechanismen, welche sowohl innerhalb des gleichen Prozessors, wie auch zwischen Programmen auf verschiedenen mit Netzwerk (typisch LAN) gekoppelten Prozessoren eingesetzt werden. Hierzu gibt es einerseit die sogenannten Remote Procedure Calls (RPC), die Sockets vom BSD-Unix sowie neuerdings das TLI (Transport Layer Interface) von Sun.

Bei den Highlevel-IPC-Services handelt es sich um sogenannte Middleware, also Software-Pakete, welche als defacto-normierte Schicht zwischen Applikations-Programm und einem darunterliegenden noch nicht ganz normierten System-Plattform befindet. Middleware kann auch die Aufgabe haben, ein gegenüber Applikations-Programmen normiertes, altbewährtes Kommunikations-Protokoll auf eine neuere darunterliegende Architektur anzupassen. Ein typisches Beispiel ist das CICS (Customer Information Control System, (IBM)), welches heute auf verschiedenen Nicht-Host-Plattformen verfügbar ist (AIX, HP-UX, OS/2, ua.). Damit kann auf höherer Ebene ein etabliertes Kommunikations-Protokoll verwendet werden, um das auf dem Host verfügbare CICS zu bedienen. Andere Produkte sind ToolTalk ([5]) von Sun oder der Broadcast Message Server von HP, welche zur Kopplung und Kommunikation zwischen verschiedenen Tools (typisch in CASE und SW-Entwicklungsumgebungen) dienen.

Auf einer ähnlichen Stufe befindet sich die Interprozess-Kommunikations-Bibliothek Express von ParaSoft Corp. ([10]) welches das Austauschen von Meldungen aus C- und Fortran-Programmen unterstützt.

Mit fortschreitender Standardisierung und Entwicklung von DCE-kompatiblen Produkten, werden zum Teil gewisse Middleware-Produkte verschwinden, während sich andere eben der DCE-Umgebung angepassen werden. Altbewährtes ist in der Regel häufig eingesetzt und dadurch trotz neuerer Technologien, nicht so schnell ersetzbar.

Im folgenden wollen wir uns hauptsächlich mit den beiden ersten Schichten befassen, also sowohl mit Local-IPC wie mit Remote-IPC. Dabei wird uns der Unterschied nur am Rand interessieren, da für verteilte Applikationen, sich der Entwickler wie der Anwender nicht darum kümmern möchte, ob nun prozessorgebunden oder -ungebunden kommuniziert wird. Er soll sich ein Modell vorstellen, in dem mehrere Prozesse auf irgendwelchen Maschinen ablaufen und sich gegenseitig Informationen mittels IPC zustellen können.

3 IPC-Topologien und Protokolle

Es gibt drei Hauptprotokolle, die für IPC massgebend sind:

  • Conversational Mode
  • Remote Procedure Call (RPC)
  • Message Passing (Message Queues)

3.1 Conversational Mode

Der Conversational Mode (s.Abb.3) stellt eine virtuelle Verbindung zwischen zwei Prozessen dar. Man kann dies ähnlich einem Telefongespräch vorstellen, bei dem der Anrufer zuerst den Empfänger anwählen muss, dieser muss den Anruf beantworten (Telefon abnehmen) und sich bereit erklären mit dem Anrufer zu kommunizieren. Darauf folgt das ''Ping-Pong'' von Datenaustausch, abwechslungsweise zwischen den beiden Teilnehmer.

Während dieses Protokoll zwar durch die fixe etablierte Verbindung recht eingeschränkt und synchron ist, hat es den Vorteil für grössere Datenmengen effizienter zu sein, da die Verbindung nicht jedesmal neu etabliert werden muss, wie dies bei den andern beiden, RPC und Message Passing, der Fall ist. In diese Kategorie fallen IBMs APPC (Advanced Programm to Programm Communication), Sockets in BSD sowie die verbindungsorientierte Verwendung von TLI (Sun).

Abb. 3: Conversational IPC

unix

3.2 Remote Procedure Call (RPC)

Das Verfahren der Remote Procedure Calls (RPC) ([4]) ist heute für verteilte Applikationen und vorallem für Client/Server-Anwendungen das häufigst gebrauchte Mittel. Im Programm sieht es einem normalen Funktionsaufruf sehr ähnlich. In der Ausführung hingegen werden die Funktionsparameter in eine Meldung verpackt und an den evtl. entfernten Server geschickt. Dieser packt sie aus und ruft damit die bei ihm lokale Funktion (Procedure) auf. Das Resultat dieser Funktion wird wiederum in eine Meldung verpackt und an den aufrufenden Prozess zurückgeschickt, dort ausgepackt und als Funktionswert (oder veränderte Parameter) zurückgegeben. Der aufrufende Prozess hat also eine entfernte Prozedur aufgerufen woraus der 'Remote Procedure Call' seinen Namen erhielt (Abb.4)

Abb. 4: Remote Procedure Call.

unix

Auf den ersten Blick, scheint dieser Mechanismus sowohl einfach im Konzept wie auch einfach in der Bedienung. In der Praxis zeigen sich aber folgende Grenzen:

  • Die Definitionen von RPCs in Programmen müssen mit einer speziellen Zwischensprache (IDL) und dem entsprechenden Präprozessor übersetzt werden. Dieser Vorgang erfordert etwas mehr Spezial- und Systemkenntnisse als üblich.
  • Der aufrufende Prozess (Thread) blockiert bis der aufgerufene Prozess die Funktion ausgeführt hat. Ein Weiterarbeiten des Client-Prozesses ist nur möglich, wenn er für den Aufruf einen eigenen Thread generiert, was dann die RPCs nicht mehr als nur Prozeduraufrufe erscheinen lässt.

In der Regel werden solche RPCs in Applikationsbibliotheken verpackt und von Systemspezialisten entworfen und programmiert. Der Anwendungs-Entwickler ruft dann wirklich nur eine Funktion auf, welche ihrerseits dann die RPC-Mechanismen aktivieren.

Jede Remote Procedure erhält eine spezielle Nummer (eindeutig), über die sie im System den Standort der Implementation der Prozedur findet. Die Verwaltung dieser Nummern muss natürlich so gemacht werden, dass im Adressbereich des Netzwerkes in dem RPC verwendet werden, diese Nummern eindeutig sind. In OSF/RPC wird dies vom UUID-Generator (Universal Unique Identifier) unterstützt. Ein weiteres Problem, das wir teilweise auch bei Programmbibliotheken kennen, ist die Version. Wenn ein Client-Programm via RPC eine Prozedure eines Servers aktiviert, dessen Programm aber inzwischen geändert wurde, dann muss der Server entscheiden, ob er eine ältere Version eines RPCs noch unterstützen kann oder nicht. Das zeigt auch, dass in einem verteilten System das Administrieren von Programmversionen wesentlich aufwendiger wird, wohl geplant und durchdacht sein muss, als dies bereits bei zentralen Applikationen der Fall war. Eine weitere Aufgabe, die bei allen drei Mechanismen zu lösen ist, bildet die unterschiedliche Datenrepräsentation auf verschiedenen Rechnerarchitekturen. Der Entwickler und RPC-Benutzer, weiss ja nicht auf welchem Rechner die Server-Applikation läuft. Es ist deshalb die Aufgabe der Interface-Sprache und eines Runtime-Services diese Datenkonversion korrekt vorzunehmen. Das Konzept ist so, dass jeder sendende Rechner seine Daten auf ein standardisiertes Netzwerk-Format (z.B. XDR = External Data Representation (SUN), NDR = Network Data Representation (OSF)) formatiert. Der empfangende Rechner wandelt dann die Daten wieder auf seine Datendarstellung zurück. Wieso muss man dies überhaupt machen? Als einfaches Beispiel nehmen wir die Datenrepräsentation einer kurzen Integerzahl auf einem Intel 80486 und auf einem Motorola 68000-xx. Auf dem Intelprozessor wird im Speicher zuerst Bit 0-7 dann Bit 8-15 abgespeichert, während beim 68000 zuerst Bit 8-15 dann 0-7 abgespeichert wird. Wenn man ohne Datenkonversion eine kurze Integerzahl mit dem Wert 1 von einem 68000 auf einen 80486 schickt, repräsentiert diese Integerzahl dort den Wert 256, ein ''kleiner'' Unterschied.

3.3 Message Passing (MP)

Das Prinzip des Message Passing (s. Abb. 5) kann stark mit unserer Briefpost verglichen werden. Das Programm verpackt seine Daten, setzt Absender und Empfängeradresse drauf und übergibt das ''Paket'' an einen ''Message Passing Service''. Dieser sucht sich den ''Briefkasten'' (Message Queue) des Empfängers aus und legt das ''Paket'' dort ab. Das Empfängerprogramm holt sich bei günstiger Gelegenheit dieses Paket ab und verarbeitet es. Eventuell sendet es daraufhin eine Antwort an den Empfänger zurück.

Abb. 5: Message Passing

unix

Wir unterscheiden zwischen zwei verschiedenen Methoden von Message Passing:

  • Synchrones Message Passing
  • Asynchrones Message Passing

Beim synchronen Vorgang, müssen Empfänger- wie Senderprozess sich zu einem bestimmten Zeitpunkt treffen (vgl. Rendezvous in ADA), zu welchem sie die Daten austauschen. Dieser Vorgang hat den Vorteil, dass keine Speicherprobleme durch einen schnellen Sender und einem langsameren Empfänger auftreten. Als Nachteil muss man werten, dass natürlich Deadlocks (Blockaden) auftreten können, weil zwei Prozesse (evtl. über einen Dritten) Daten vom andern erwarten. Ebenfalls kann der Sender oder Empfänger nicht weiterarbeiten, wenn der Partner nicht bereit ist (ähnlich wie bei RPC ohne zusätzliche Threads). Das synchrone Message Passing in Kombination mit Timeouts wird häufig in Realtime- und Prozesssteuerungs-Systeme eingesetzt, weil damit das Verhalten besser im voraus zu beurteilen ist, besser getestet werden kann und auch stabiler ist. Ein synchron arbeitendes System benötigt weniger dynamisch allozierten Speicherplatz als eines mit asynchronem Message-Passing.

Beim asynchronen Vorgang, kann der Senderprozess weiterarbeiten, nachdem er die Meldung in die Message Queue (Briefkasten) des Empfängers gelegt hat. Dies bedingt natürlich, dass darin genügend Speicherplatz alloziert werden kann, um die Meldung aufzunehmen. Der Empfänger kann entweder auf die Meldung warten (Blocked Receive) oder wird beim Eintreffen der Meldung mit einem Event (Signal) darauf aufmerksam gemacht, dass eine Meldung im Briefkasten vorhanden ist. Die asynchrone Form entspricht mehr unserer Denkweise und wie unsere Organisationen operieren. Um nämlich geeignete Algorithmen für verteilte Applikationen zu finden, kann man sich an unseren Organisations-Techniken orientieren. Die humanen Organisation sind exellente Beispiele für verteilte und echtparallel operierende Systeme.

Für die entsprechende Applikation sollte die geeignete Form gewählt werden. Viele Bibliotheken und Pakete lassen sich für beide Verfahren einfach konfigurieren oder parameterisieren. Ebenfalls kann man mit dem asynchronen Verfahren auch ein synchrones Verfahren simulieren, indem der Sender auf eine Reply-Meldung wartet, welche ihm bestätigt, dass der Empfänger die Meldung entgegen genommen hat. Damit wären wir wieder bei dem Request-Reply-Schema, das auch bei RPC dem Entwickler aufgezwungen ist.

Ebenfalls gibt es Mischformen von Sende- und Empfangs-Operationen. Man unterscheidet zwischen:

unix

Wie bei allen verteilten Systemen, spielt die Adressierung auch beim Message Passing eine zentrale Rolle. Hier die geeignete Form zu finden bedarf noch einiges an Standardisierung. Trotzdem ist es angebracht auf Basis von symbolischen Adressen zu operieren, welche dann via eine Übersetzung - z.B. via Directory Service - in eine eindeutige Adresse im Netzwerk umgewandelt werden kann.

Obwohl RPC sehr stark verbreitet ist und als dominant wirkt, zeichnet sich ein Trend ab, dass in Zukunft Programme vermehrt auf der Basis von Message Passing arbeiten werden. Während RPC sehr geeignet für die Client/Server-Architektur ist, eignet sich Message Passing für zukünftig stark verteilte Systeme mit Peer-to-Peer-Kommunikation, worin jeder mit jedem kommunizieren kann. Für den Anwendungsprogrammierer zeigt sich die Kommunikation zu andern Prozessen auch transparenter, als dies bei RPC der Fall ist.

Wenden wir uns kurz der objektorientierte Programmierung zu, so hören wir oft die Aussage: ''Objekt A schickt Objekt B eine Meldung'', wenn es darum geht, dass Objekt A eine Methode (Operation) eines anderen Objektes aufruft. Das lässt einerseits den naheliegenden Schluss zu, dass Meldungen für verteilte Prozesse wie eine Methode für Objekte zu betrachten sind. Diese Annahme erhärtet sich, wenn man dan Entwurf von verteilten Systemen mit einer objektorientierten Design-Methode (wie z.B. Booch [3]) macht und sieht, dass die einzelnen Prozesse nichts anderes als parallel laufende Objekte sind, die verschiedene Operationen (Methoden) zur Verfügung stellen und die Aufträge via Meldungen empfangen (Methode aktivieren). Dieses Vorgehen hat der Autor bereits vor Jahren anhand einer meldungsorientierten Programmiersprache gezeigt ([8]). Vergessen wir dabei auf der RPC-Seite nicht, dass natürlich auch RPC ein direkter Weg ist, Operationen von verteilten Objekten (oder Prozessen) zu aktivieren (vgl. [12]).

Wenn man wieder auf die DCE-Architektur von OSF schaut, worin RPC seinen festen Platz hat, wäre Message Passing im Bereich ''Other Fundamental Services'' basierend auf RPC zu positionieren. Damit wäre der unterliegende Datenaustausch durch OSF/RPC standardisiert und darauf das Message-Passing aufgebaut, das für eine einfache, transparente Programmierung in verteilten Systemen verwendet werden kann.

4 IPC-Grundmechanismen in UNIX V

Wie erwähnt bietet UNIX System V einige Local-IPC-Mechanismen standardmässig an, welche heute hauptsächlich für die Kommunikation zwischen Programmen eines abgeschlossenen Applikations-System verwendet werden aber noch wenig für den Austausch zwischen Applikationen verschiedener Hersteller. Nachfolgend sind diese Mechanismen kurz charakterisiert.

4.1 Pipe

Wie einleitend erwähnt, ist der einfache aber mächtige Pipe-Mechanismus so alt wie UNIX und hat UNIX zu seiner Flexibilität verholfen. Es handelt sich dabei um einen Buffer, in welchen der produzierende Prozess hineinschreibt und der konsumierende Prozess die Daten herausliest. Der Pipe-Systemaufruf kann zwischen zwei Prozessen verwendet werden, wenn entweder beide vom gleichen Prozess abstammen (Parent) oder einer vom andern Prozess abgespaltet (fork (2)) wurde. Der Mechanismus welcher anfangs als Basis-Systemaufruf (pipe(2)) geführt wurde, wird heute durch eine zusätzliche Version ergänzt, die sich etwas konfortabler gestaltet. Der C-Aufruf:

pfid = popen (''ls -l'', ''R'');

eröffnet einen neuen Shell-Prozess, in welchem der Befehl ''ls -l'' (Verzeichnis anzeigen) ausgeführt wird und die Ausgabe kann darauf mit den gängigen FILE-Streambefehlen (fget, fscanf, fgets, fprintf etc.) wie wenn die Daten von einem File kämen, bearbeitet werden.

4.2 Named Pipe (FIFO)

Die Einschränkung der einfachen Pipe, ist beim FIFO oder der ''Named Pipe'' aufgehoben. Voneinander unabhängige Prozesse können miteinander bidirektional kommunizieren, indem beide auf die Pipe zugreifen, die im Filesystem zum Beispiel mit dem Befehl '/etc/mknod pipexy p' kreiert wurde. Die Daten werden mit den System-Calls write(2) und read(2) ins FIFO geschrieben resp. herausgelesen. Diese Operationen gelten als unteilbar, das heisst, auch wenn der Prozess unterbrochen wird, wird der übergebene Datenblock ganzheitlich hineingeschrieben. Named Pipes gehören heute in jedes modernere Betriebssystem, sind auch z.B. in OS/2 oder NT vorhanden und erlauben darum eine einfache und teilweise portierbare Interprozess-Kommunikation.

4.3 Message-Queues

Die oben bereits ausführlich beschriebene IPC-Topologie, das Message-Passing, kann unter UNIX mit Message-Queues für lokale IPC implementiert werden.

Ein Prozess kann eine solche Message-Queue - ähnlich einem File - kreieren. Anstelle des Filenamens verwendet man eine 32-Bit-Zahl, der sogenannte Key (vom Typ key_t=long). Andere Prozesse können sich dann ebenfalls einen Zugriff auf die Message-Queue verschaffen, indem sie den gleichen Key bei der Eröffnung (msgget(2)) angeben. Die Queues können wie Files für den Eingentümer, die Gruppe oder für alle andern geschützt werden. Typisch wäre, dass der Eigentümer-Prozess lesen und schreiben darf, während die andern Prozesse nur hineinschreiben dürfen. Das Lesen und Schreiben erfolgt mit den Befehlen msgsnd resp. msgrcv. Durch die Angabe der entsprechenden Parameter kann man wählen zwischen blockierendem und unblockierendem Senden resp. Empfangen. Eine gewisse Einschränkung bei Message-Queues sind ihre beschränkte Grösse. Obwohl bei der Kernel-Generierung parameterisierbar, liegt die Grösse der Queues typisch bei 2 KB oder 8 KB, in Ausnahmefällen 64 KB. Der Sender muss also damit fertig werden, wenn er auf der Empfängerseite einen langsameren Prozess hat, der seine Message-Queue nicht schnell genug abarbeiten mag.

Eine Meldung hat ein sehr einfaches Format. Eine long-Variable bestimmt den Typ der Meldung, gefolgt von einer Sequenz von Bytes, die Daten. Der Meldungstyp kann beim Empfangen zur Prioritätssteuerung verwendet werden. Man kann dabei angeben, dass man nur einen bestimmten Typ von Meldung empfangen will oder alle Meldungen, die einen kleineren oder gleichen Typ haben wie der angegebene Parameter. Message-Queues sind wesentlich einfacher anzuwenden wie RPCs. Dabei muss man aber beachten, dass was man bei RPCs via der Interface Definitions Sprache (IDL) macht, nämlich die Datentypen und Strukturen der Parameter zu spezifizieren, beim Message-Passing (mit Message-Queues) noch von Hand macht, nämlich die Struktur und die Typen zu spezifizieren, welche in einer Meldung mitgeschickt werden. Verwendet man dabei eine objektorientierte Sprache wie z.B. C++, kann dies durch Ableitung von einer Basis-Meldung aber wiederum sehr einfach gemacht werden.

Eine schöne Eigenheit der Message-Queues (generell bei Message Passing) ist, dass sich der Anwender nicht um Synchronisation zu kümmern braucht. Bei den UNIX-Message-Queues übernimmt das System die Synchronisation, das heisst eine Meldung wird immer als ganzes in die Queue des Empfängers geschrieben und nicht etwa in Teilen. Dadurch können Meldungen auch zur Synchronisation auf höherer Ebene verwendet werden.

In der Praxis bewähren sich die Message-Queues sehr gut. Für komplexere Systeme muss man aber einige zusätzliche Funktionen hinzufügen, damit, verpackt in eine Bibliothek, der Anwender einen zuverlässigen Message-Passing-Dienst zur Verfügung hat.

4.4 Shared Memory

Sollen mehrere Prozesse schnell und häufig auf grosse Datenbestände zugreifen können, die in einem System evtl. laufend ändern, wird IPC mittels Message-Queues oder Named Pipes bald zu langsam. Die Lösung dazu heisst Shared Memory, also gemeinsamer Speicherbereich für zwei oder mehrere Prozesse, welche sonst nicht den gleichen Adressraum haben. Beim Shared Memory, fordert ein Prozess ein Speichersegment, spezifiziert durch Key (wie oben bei Message-Queues beschrieben) und Grösse vom Betriebssystem an. Andere Prozesse können sich nun mit dem gleichen Key auch Zugriff auf diesen Speicherbereich verschaffen. Via eine Referenz können alle Prozesse in diesen Speicherbereich sowohl schreiben wie auch davon lesen, je nachdem wie die Zugriffsberechtigung vom kreierenden Prozess gesetzt wurde. Diese Zugriffe finden in der Regel mit hoher Durchsatzrate statt, da ja von den Prozessen direkt, fast wie auf den eigenen Adressraum zugegriffen wird. Dabei darf man aber einen Aspekt, den der Synchronisation, nicht vergessen. Im Gegensatz zu Message-Queues sind Shared-Memory-Segmente nicht automatisch synchronisiert. Dazu setzt man am Besten entweder Semaphoren (ebenfalls unter UNIX System V verfügbar) oder Meldungen ein. Ansonsten kann die Verwendung von Shared-Memory sogar als einfacher als Message-Queues eingestuft werden.

Wer die Eigenheiten der UNIX System V IPC in der Praxis kennen lernen will, der ist gut beraten, wenn er den Text ''Parallele Prozess unter UNIX'' ([7]) zur Hand hat, in dem UNIX-IPC u.a. sehr gut, mit Beispielen beschrieben wird.

4.5 Implementationshinweise

Ein Problem, stellt sich sowohl bei der Verwendung von Message-Queues, Shared-Memory wie bei Semaphoren, die ihre Identifikation alle über den erwähnten 32-Bit-Key erhalten.

Sofern man sich an ein bestimmtes Verteilschema oder an einen Verteilalgorithmus hält, wie die Keys unter den Applikationen zugeteilt werden, besteht kein eigentliches Problem. Wenn aber Applikationen von verschiedenen Herstellern diese IPC-Mechanismen verwenden und unterschiedliche Verteilschemen oder -Algorithmen benutzen, dann kann es zu Überschneidungen von Keys kommen. Als Lösung wird empfohlen den Systemaufruf ''ftok (path, id)'' zu verwenden, welcher aufgrund eines bestehenden Filesystemeintrags (path) und einer von der Applikation vergebenen Identifikation (id) einen einmaligen Key retourniert, der wiederum zur Identifikation der verwendenden IPC-Ressource benutzt werden kann. Sofern sich möglichst alle an diesen System-Call halten, sollte es auch nicht zu Überschneidungen kommen.

Weiter empfiehlt es sich bei der Verwendung von Message-Queues, pro Prozess genau eine Message-Queue zu kreieren (KEY könnte z.B. der Prozess-Identifier sein), über die der Prozess die Meldungen empfängt. Das erlaubt dem Prozess nur von einem Kanal Meldungen zu erwarten, ohne komplexe Abfrage-Algorithmen bewerkstelligen zu müssen. Dies ist natürlich keine Forderung, denn es kann absolut angebracht sein, dass ein Prozess mehrere Message-Queues hat, um zu mehreren externen Prozessen eine gerichteten Kommunikations-Kanal zu haben. Dies muss je nach Anwendung und Durchsatzanfordernissen entschieden werden. Zu beachten ist aber, dass die maximale Anzahl von Message-Queues pro Benutzer und pro System beschränkt sind (kann im Kernel konfiguriert werden).

Sollten einmal, beim Test oder beim unkontrollierten Abbrechen eines Programmes IPC-Ressourcen (Message-Queues, Shared-Memory-Segmente, Semaphoren) ''liegen'' bleiben, so helfen die beiden Kommandos ipcs zum Anzeigen der IPC-Statusliste und ipcrm zum forcierten Löschen von unerwünschten Ressourcen.

Baut man in einem Projekt auf einem Message-Passing-System-Service auf und setzt dabei auch eine objektorientierte Programmiersprache wie C++ ein, lohnt es sich die IPC-Mechanismen in Klassen zu verpacken, um die Anwendung derer zu vereinfachen und sicherer zu machen ([1]). Der Autor hat solche Klassen, welche UNIX-Prozesse (fork) und Message-Passing mit Message-Queues unterstützen in mehreren Versionen entwickelt und damit sehr gute Erfahrungen gesammelt. Vorallem der Aspekt, ganze Objekte, unabhängig von ihrer Komplexität via Message-Queues an einen andern Prozess zu senden, eröffnet neue, sehr interessante und mit Hilfe von OO sehr mächtige Perspektiven.

5 Zusammenfassung

In diesem Artikel wurde versucht einen groben Überblick über die Interprozess-Kommunikation zu geben. Ausgehend vom gewohnten Kommunikations-Schichtenmodell (OSI), wurde aufgezeigt welche Aufgaben, Topologien und Protokolle sich in der ''Data Exchange Facility'' verbergen.

Dabei wurde auch versucht, einen Vergleich zwischen RPC, wie in OSF/DCE verwendet und der Message-Passing-Methode zu geben. Die Arbeiten von OSF, vorallem im Teilgebiet DCE wird zukunftsbestimmend sein.

Ebenfalls im Überblick wurden die IPC-Mechanismen von UNIX System V gestreift und einige Tips für die Implementation gegeben.

Zu erwähnen wären noch die Sockets, die im BSD Unix zur Interprozess-Kommunikation auch über Rechnergrenzen hinweg verwendet werden. Die Verwendung von Sockets ist einfach aber von der Datensicherheit eher schwach. Da es nicht Bestandteil von UNIX System V ist, wird deren Verwendung in Neuentwicklungen von SUN nicht mehr empfohlen. Als Alternative dazu sollen TLI oder andere Mechanismen verwendet werden.

Die Verwendung der behandelten IPC in verteilten Systemen, betrifft zukünftig auch bald Objekte, welche verteilt werden müssen. Die objektorientierte Technologie, kann sowohl beim Einsatz von IPC-Klassen-Bibliotheken wie aber überhaupt beim Entwerfen von verteilten Applikationen von grosser Bedeutung sein. Dabei darf man den Object Request Broker von der Object Management Group nicht aus den Augen lassen, denn daraus werden zusammen mit DCE von OSF die Standards der Zukunft wachsen ([9],[2]).

6 Literatur

J.Th.Berry, ''The Wait Group's C++ Programming'', Howard W. Sams&Company, Indianapolis, USA.
T. Beyer, ''Objektbörse, CORBA-OMG Standard für verteilte Objekte'', iX 2/93, S. 24-33.
G.Booch, ''Object Oriented Design with Applications'', The Benjamin/Cummings Publishing Company, Inc. New York, ISBN 0-8053-0092-0, 1991.

M.Busch, ''Erste Schritte, Hilfestellung bei der RPC-Programmierung durch System-Tools'', iX 6/1993, S.184-186.
M.Busch, ''Einführung in Suns ToolTalk-Service'', iX 5/1993, S.122-127.
R.J.Cypser, ''Communications for Cooperating Systes, OSI, SNA and TCP/IP'', Addison-Wesley Publishing Company Inc., ISBN 0-201-50775-7, 1991.
Danneger/Geugelin, ''Parallele Prozesse unter UNIX'', Carl Hanser Verlag München/Wien, ISBN 3-44-15911-8, 1991.
A. Koch/TSE. Maibaum, ''Message oriented Language for System Applications'', Proceeding The 3rd International Conference on Distributed Computing Systems, Miami/Florida, October 1982.
OSF,''DCE Application Development Guide'', Open Software Foundation, Cambridge, USA, 1992.
ParaSoft, ''A Tutorial Introduction to Express'', Version 3.2, ParaSoft Corp., 2500, E.Foothill Blvd., Pasasdena, CA 91107.
M.J. Rochkind, ''Advanced UNIX Programming'', Prentice-Hall Inc., Englewood Cliffs, New Jersey, ISBN 0-73-011818-4, 1985.
A.Schill, M.Person, ''Verteilte objektorientierte Erweiterung des OSF Distributed Environments'', Offene Systeme Nr.2 /1993, S.94-100, Springer International, 1993.