Die Community zu .NET und Classic VB.
Menü

InterProzessKommunikation

 von 

Übersicht 

In dieser Kolumne wird es um InterProzessKommunikation und im Speziellen um Pipes gehen.

Ein zur Kolume gehörendes Beispielprojekt sollte für alle Interessierten klären, wie InterProzessKommunikation unter Visual Basic realisiert werden kann.

Einleitung  

Die erste Frage zum Thema sollte natürlich sein: "InterProzessKommunikation, was bedeutet das überhaupt?". Diese Frage ist recht einfach zu beantworten.

InterProzessKommunikation beschreibt einen Vorgang bei welchem zwei oder mehr Prozesse Daten austauschen.

Sinn  

Wofür müssen Prozesse Daten austauschen?

Häufig geht es darum, dass einer der Prozesse Berechnungsergebnisse, Daten von Geräten und ähnliches für andere Prozesse zum Abruf bereithält. Auch die klassischen Chats sind Beispiele für InterProzessKommunikation.

InterProzessKommunikation ist folglich omnipräsent.

Möglichkeiten  

Unter Windows gibt es eine Reihe von Mechanismen um InterProzessKommunikation zu betreiben.

Die MSDN unterscheidet diese Mechanismen hier nach der Frage, ob mit Prozessen auf dem selben oder auch mit Prozessen auf anderen Rechnern kommuniziert werden soll.

Zur Gruppe die nur auf dem selben Rechner arbeiten zählen u.A.

  • COM
  • Anonyme Pipes
  • Gemeinsamer Speicher

Im Netzwerk verwendet man

  • DCOM
  • NamedPipes
  • Windows Sockets

Ergänzung am 30.06.03

Eine weitere Möglichkeit zur InterProzessKommunikation über Netzwerke, sind Mailslots. Im Vergleich zu Pipes haben sie den Nachteil, dass man keine Empfangsbestätiung wie bei Pipes hat. Vorteilhaft ist, dass es Broadcasts gibt und Mailslots auch unter Windows 9x funktionieren.

Vielen Dank an "The Condor" für den Hinweis.

Einschränkungen

Diese beiden Listen sind nicht vollständig.

Zum Einen habe ich nur solche Mechanismen aufgeführt, die meines Wissens auch mit VB realisierbar sind.

Zum Anderen habe ich die in Daten zwischen Prozessen austauschen beschriebene Möglichkeit zum Datentransfer über SendMessage ausgelassen, da ich dieses Verfahren für ehr ungeeignet halte. Aber diese Entscheidung mag jedem selbst überlassen sein.

Erklärungen

Zu COM ist zu sagen, dass jeder fortgeschrittene VB-Programmierer COM bei ActiveX-DLLs und ActiveX-Exen verwendet. DCOM ist hier quasi nur die Erweiterung auf die Netzwerkebene.

WINdows SOCKets (Winsock) sind, denk ich mal, jedem VB-Programmierer bekannt.

Zur Kommunikation über gemeinsamen Speicher kann ich nur wenig sagen. Ein VB Beispiel habe ich noch nicht gesehn, aber es sollte machbar sein. Hierbei ist es dann allerdings notwendig Prozesssynchronisation zu betreiben. Wie dies zu realisieren ist, kann in der Kolumne 7 nachgelesen werden.

Pipes  

Oder Rohre (laut Dictionary) sind ein Mechanismus, den ich etwas ausführlicher beschreiben möchte.

Prinzip

Es gibt erst einmal zwei Enden einer Pipe. Jedes Ende kann (wenn gewünscht) Daten senden und empfangen. Die Daten erreichen dann jeweils das andere Ende.

Die Enden sind i.d.R. zwei verschiedene Prozesse. Eines dieser Enden wird als Server bezeichnet. Das andere als Client.

Modi

Es gibt weiterhin noch eine Unterscheidung in der Betriebsart. Pipes die im Message-Modus arbeiten denken in Nachrichten. Pipes im Byte-Modus denken byteweise.

Der Unterschied soll an einem kleinen Beispiel verdeutlicht werden. Wenn man den String "Hallo" über eine Message-Modus-Pipe schickt, kommt am anderen Ende auch wieder "Hallo" in einem Stück an.

Bei einer Byte-Modus-Pipe bekommt man das "Hallo" byteweise. D.h "H", "a", "l", "l", "o". Um effektiv lesen zu können, ist es jedoch auch möglich, sofern mehrere Bytes anliegen, diese in einem Rutsch zu lesen.

NamedPipes  

NamedPipes haben im Gegensatz zu (anonymen) Pipes einen festen Namen, über den sie identifizier- und ansprechbar sind.

NamedPipes können nur auf NT-Betriebssystemen verwendet werden. Der Name einer NamedPipe ist ein UNC-Pfad-/Dateiname.

Durch die eindeutige Identifizierbarkeit können NamedPipes auch zur InterProzessKommunikation verwendet werden, wenn sich die Enden der Pipe auf unterschiedlichen Rechnern befinden.

Umsetzung  

Umsetzen kann man den Zugriff auf NamedPipes unter Visual Basic durch das Einbinden verschiedener API-Funktionen.

In der MSDN finden sich hierzu ausführliche Beschreibungen.

Eine wichtige Rolle spielen hierbei ReadFile und WriteFile. Über diese beiden Funktionen, die normalerweise zur Dateibearbeitung dienen, kann man auch Daten an Pipes senden bzw. von diesen empfangen. Entsprechende Handles bekommt man von CreateNamedPipe und CreateFile.

Beispielprojekt  

Um praktisch zu erleben, was NamedPipes sind und wie sie funktionieren, habe ich ein kleines Beispielprojekt geschrieben.

Dieses enthält eine Klasse, welche alle verwendeten Funktionen zum Zugriff auf NamedPipes kapselt. Hierdurch sollte es auch Anfängern möglich sein, NamedPipes zu verwenden.

Das Beispielprojekt ist ein Minichat, welcher den Datentransfer über eine NamedPipe erledigt.

Einschränkungen

Zu bemerken sei, dass das Beispielprojekt eine Einschränkung hat.

Der Server muss die Pipe, nachdem der Client die Verbindung beendet hat, neu erstellen.

Diese Einschränkung ist meines Erachtens nicht durch die API vorgesehen. Sobald ich den Fehler gefunden habe, werde ich die Korrektur publizieren.

Ergänzungen

Seit dem 02.07.2003 kann nun auch zu NamedPipes verbunden werden, welche sich auf anderen Rechnern befinden. Da ich leider selbst nicht die Ressourcen habe, dies zu testen, würde ich mich über positive/negative Kritiken freuen.

Download des Beispielprojektes 

Schlusswort  

Ich hoffe mit dieser Kolumne etwas Interesse am Thema gewecket zu haben.

Mit freundlichen Grüßen
Florian Rittmeier

Ihre Meinung  

Falls Sie Fragen zu diesem Artikel haben oder Ihre Erfahrung mit anderen Nutzern austauschen möchten, dann teilen Sie uns diese bitte in einem der unten vorhandenen Themen oder über einen neuen Beitrag mit. Hierzu können sie einfach einen Beitrag in einem zum Thema passenden Forum anlegen, welcher automatisch mit dieser Seite verknüpft wird.

Archivierte Nutzerkommentare 

Klicken Sie diesen Text an, wenn Sie die 13 archivierten Kommentare ansehen möchten.
Diese stammen noch von der Zeit, als es noch keine direkte Forenunterstützung für Fragen und Kommentare zu einzelnen Artikeln gab.
Aus Gründen der Vollständigkeit können Sie sich die ausgeblendeten Kommentare zu diesem Artikel aber gerne weiterhin ansehen.

Kommentar von Uwe Hollmeier am 04.04.2007 um 22:53

Hallo Florian, prima Beispiel, hat mir gut weiter geholfen. Frage: Gibt es bereits eine Lösung für die Einschränkung, dass nach dem Beenden der Pipe-Verbindung die Pipe jedesmal neu erstellt werden muss? Für ein Launchprogramm auf einem Remotesystem, das im Autostart eingebunden ist, ist das ziemlich unbefriedigend. Würde mich freuen. Gruß Uwe

Kommentar von Christoph Muschner am 31.01.2006 um 11:28

Hallo,
sehr schönes, anschauliches Beispiel, welches auch noch funktioniert!
Gibt es so etwas auch schon für VB.NET 2005 und den neuen IPCChannels?
mfg
Christoph Muschner

Kommentar von Florian Rittmeier am 04.01.2005 um 11:57

Hallo Leute,

also ich hab nochmal ein wenig nachgelesen und ausprobiert.

@Matthias:
In der MSDN-Library steht, dass bei Angabe des Wertes NULL Systemaccount, Administratoren und der Ersteller Vollzugriff haben. Mitglieder der Gruppen "Jeder" und "Gäste" können lesend auf die Pipe zugreifen. Klar, zum Schreiben ist das dann noch ein bissel zu wenig.

@Alle:
Dem ein oder anderen ist vielleicht aufgefallen, dass beim Versenden von mehreren Nachrichten, nur eine Nachricht angezeigt wird. Dies hängt mit meiner ungenügenden Implementierung zusammen. Tatsächlich werden alle Nachrichten auf einmal abgerufen. Dies kann man leicht dadurch feststellen, dass man vor der Anzeige der Nachricht, diese per Debug.Print testweise ausgibt.
Problem ist, dass ans Ende jeder Nachricht ein vbNullChar angehängt ist. Die Messagebox-Funktion reagiert hierauf etwa s empfindlich, d.h. sie bricht an dieser Stelle die Ausgabe ab.
Für den Anfang würde ich daher empfehlen vor dem Aufruf der Messagebox-Funktion folgenden Code auszuführen.

message = Replace(message, vbNullChar, " ")


Gruß Florian

Kommentar von Florian Rittmeier am 04.01.2005 um 11:21

Hallo Florian,

Du solltest bei der nächsten Überarbeitung noch eine Zeile einfügen, dass vor dem Schließen einer PIPE die Funktion FlushFileBuffers aufgerufen wird.

Gruß Florian

Kommentar von Matthias am 05.02.2004 um 08:21

Hier mal noch die Code-Erweiterung um ein NamedPipe mit "Everyone"-Rechten einzurichten:

Zusätzliche Deklaration:

Private Declare Function GlobalAlloc Lib "kernel32" (ByVal wFlags As Long, ByVal dwBytes As Long) As Long
Private Declare Function GlobalFree Lib "kernel32" (ByVal hMem As Long) As Long
Private Declare Function InitializeSecurityDescriptor Lib "advapi32.dll" (ByVal pSecurityDescriptor As Long, ByVal dwRevision As Long) As Long
Private Declare Function SetSecurityDescriptorDacl Lib "advapi32.dll" (ByVal pSecurityDescriptor As Long, ByVal bDaclPresent As Long, ByVal pDacl As Long, ByVal bDaclDefaulted As Long) As Long

Const SECURITY_DESCRIPTOR_MIN_LENGTH = (20)
Const SECURITY_DESCRIPTOR_REVISION = (1)


Erweiterung:
'Create the NULL security token for the pipe
pSD = GlobalAlloc(GPTR, SECURITY_DESCRIPTOR_MIN_LENGTH)
retval = InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)
retval = SetSecurityDescriptorDacl(pSD, -1, 0, 0)
sec.nLength = LenB(sec)
sec.lpSecurityDescriptor = pSD
sec.bInheritHandle = True

retval = CreateNamedPipe("\\.\pipe\" & Name, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE, 1, 2048, 2048, 100, sec)


Beim schließen vom NamedPipe - GlobalFree nicht vergessen!
GlobalFree(pSD)


Quelle: http://support.microsoft.com/default.aspx?scid=kb;en-us;177696

Schöne Grüße
Matthias

Kommentar von Matthias am 17.01.2004 um 03:23

Zu Zugriffsrechte.
Im Beispiel-Projekt wir als Wert NULL vergeben.
Laut MS dürfen somit nur noch folgende Kennungen auf den Pipe zugreifen:
Systemaccount, Administratoren und der Ersteller.

In einem Beispiel-Projekt von MS wird wiederum beim erstellen vom Pipe eine NULL DACL angegeben und somit "jeder" Berechtigt.
Somit kann eigentlich auch jeder Zugreifen.

Wenn man aber nun über ein Netzwerk auf Named Pipes zugreifen möchte, gelten noch zusätzliche Regeln! So ist es bei 2000 und XP erstmal überhaupt nicht gestatten ohne Authentifizierung auf einen Rechner zuzugreifen. Hier wird man schon vorher geblockt.
Damit es dennoch funktioniert, muß an den "Lokale Sicherheitsrichtlinie" gedreht werden.

Gruß Matthias

Kommentar von Gerd Lobmeyer am 26.08.2003 um 13:59

Hallo, ich habe mir das Project genau angesehen und versucht es nach meiner Vorstellung zu ändern. Leider habe ich da Probleme mit daher meine Frage: Wie ist es möglich einen String (PATH) von einem Programm zum anderen zu übertragen via Pipe und eine Antwort in Form einer Zahl z.B. 0 zurücksenden für OK oder False. Mit Longwerten habe ich es schon geschafft.
Viele Grüße, Gerd

Kommentar von Uwe am 29.06.2003 um 12:28

Wie und wo muss ich den Code abändern, dass ich auch zu einem Remote-Computer verbinden kann?

Kommentar von Florian Rittmeier am 06.04.2003 um 00:29

An Uwe:
Die Antwort auf diese Frage ist sehr komplex.

Über den lpSecurityAttributes-Parameter der CreateNamedPipe-Funktion kann bestimmt werden, wer auf die NamedPipe zugreifen darf.

Im Beispielprojekt wird als Wert Null angegeben, wodurch die NamedPipe die DACL(ACL= Access Control List; DACL= ACL, welche beschreibt, wer (nicht) Zugriff auf das Objekt nehmen darf) vom erzeugenden Programm erbt. Diese unterscheiden sich folglich von Benutzer zu Benutzer. Speziell andere Gruppenzugehörigkeiten können sich, so meine Vermutung, also unvorhergesehen auswirken.

Habe bisher noch nicht überprüft, welche ACEs (ACE= Access Control Element) ein Programm im Standardfall bei einem normalen Nutzer bzw. Administratoren auf die NamedPipe überträgt.

Über entsprechende API-Funktionen kann man genau festlegen, welcher Benutzer bzw. welche Gruppe mit der NamedPipe arbeiten darf.

Da die beteiligten Rechner alle NT verwenden müssen, findet bei diesen, meines Wissens, automatisch eine Authentifikation des Users statt.
Hierdurch werden also auch Zugriffe von anderen Rechner eindeutig klassifiziert.
Wie reagiert werden soll, muss man letztlich selbst einstellen.

Soviel zum Thema Zugriff auf eine NamedPipe, die sich auf einem anderen Rechner befindet(kann auch beim lokalen Rechner Auswirkungen haben -> z.B. Terminal Server, da Multiusersystem).

Weiterhin ist es auch möglich, über das Handle der NamedPipe, die Rechte des eigenen Programmes zu ändern. Zumindest auf der Serverseite.

Wenn ich im folgenden von User spreche, meine ich ein Programm, welches unter bestimmten Userrechten läuft.

Wenn User A von Rechner A eine Verbindung zu einer NamedPipe auf Rechner B herstellt, dann kann User B, welche die NamedPipe erstellt hat, durch die Handle der NamedPipe, dem System unter gewissen Vorraussetzungen sagen, dass er nun User A ist und entsprechende Zugriffsrechte hat.
Hierdurch kann man die Sicherheit wesentlich erhöhen und muss sich um das ein oder andere nicht kümmern.

Ich hoffe, dass hat deine Frage erschöpfend beantwortet und war nicht durch zuviele Erläuterungen belastet.

MfG Florian

Kommentar von Florian Rittmeier am 06.04.2003 um 00:04

An Jonathan:
Welches Betriebssystem verwendest Du,
und wie genau bist Du vorgegangen.
Kontaktiere mich am besten per Email zur Klärung.

MfG Florian

Kommentar von Uwe am 04.04.2003 um 17:29

Welche Restriktionen (Security) können sich auf die Arbeitweise von Pipes auswirken. Sicher müssen doch bei einem LAN dem Userprozess auf einem "fremden" Rechner gewisse Rechte eingeräumt werden?

Kommentar von Jonathan am 03.04.2003 um 16:07

Das Projekt funktioniert bei mir nicht.
(NamedPipe konnte nicht erstellt werden/konnte nicht verbunden werden)

Kommentar von Florian Rittmeier am 02.04.2003 um 22:03

Hallo!
Den Abschnitt Einschränkungen bitte nicht so sehr berücksichtigen.
Habe heute Abend noch ein wenig gebastelt
und der jetzige Stand der Dinge ist:
It's not a bug, it's a feature!

MfG Florian