Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Software-Projekte der Mitglieder (https://www.delphipraxis.net/26-software-projekte-der-mitglieder/)
-   -   Klassen für einfache IPC (InterProzessCommunication) (https://www.delphipraxis.net/151224-klassen-fuer-einfache-ipc-interprozesscommunication.html)

idefix2 9. Mai 2010 19:46


Klassen für einfache IPC (InterProzessCommunication)
 
Liste der Anhänge anzeigen (Anzahl: 1)
Nachdem ich für mein Projekt so etwas brauche und nichts wirklich Fertiges gefunden habe, das man unmittelbar einsetzen kann, habe ich zwei Klassen für das einfache Versenden von Strings via Memory mapped files programmiert - die Klassen könnten aber bei Bedarf leicht für beliebige andere Datentypen angepasst bzw. erweitert werden.
Nachdem ich für meine Zwecke keine Unicode-Strings brauche, wird von allen Zeichen des Strings nur das niederwertige Byte übertragen, sodass der Puffer nur halb so gross sein muss wie bei Unicode-Zeichen. Auch das liesse sich bei Bedarf leicht ändern.
Die Kommunikation geht nur in eine Richtung, will man in beide Richtungen kommunizieren, brauchen beide Programme sowohl den Server als auch den Client.


Beim Programmieren des TIPCClient bin ich über ein Problem gestolpert, das ich nicht lösen konnte, und haBE deshalb darum herumprogrammiert. Es ist mir nicht gelungen, den Befehl OpenFileMapping so zu verwenden, dass er richtig funktioniert. Ich habe dann statt dessen CreateFileMapping mit wenn nötig gleich anschliessendem CloseHandle verwendet, ist etwas umständlicher, aber funktioniert. Für Hinweise, was an der anderen Variante (im Quellcode auskommentiert) falsch ist, wäre ich dankbar.

Die Klassen heissen TIPCServer und TIPCClient, TIPCServer dient zum Versenden der Nachrichten, TIPCClient zum Empfangen.

TIPCServer publiziert folgende Methoden:

constructor Create (const name: string; BufSize: integer);
Erzeugt ein Memory Mapped File mit der angegebenen Größe und dem angegebenen Namen. Die Grösse des Datenpuffers ist um 8 Bytes kleiner als die Grösse des Memorymapped files.
Achtung: Der Datenpuffer muss so gross gewählt werden, dass kein Überlauf entstehen kann (dass also nicht mehr Daten abgeschickt werden, als im Puffer Platz haben, bevor der Client sie abgeholt hat).

procedure Msg (const s: string);
Stellt den String S zum versenden bereit. Wenn schon ein String zum versenden bereit steht, wird dieser neue String unmittelbar an den vorigen String angehängt. Auf Empfängerseite wird #13 als Stringtrennzeichen interpretiert, d.h. der String 'abc'#13'xyz' kommt so an, als wären zwei Strings 'abc' und 'xyz' versendet worden.

procedure MsgPost;
Schickt den versandbereiten String ab.


TIPCClient publiziert folgende Methoden:

constructor Create (const name: string);
Hier muß nur der Name übergeben werden, der muss genau mit dem Namen übereinstimmen, der von TIPCServer verwendet wird.

function MitServerVerbunden: boolean;
Liefert true, wenn das MMF vom Server bereits erstellt wurde, sonst false.

function DatenDa: boolean;
Liefert true, wenn das MMF vom Server bereits erstellt wurde und neue Daten im Puffer sind, sonst false.

function GetString: string;
Holt den nächsten String aus dem Puffer. Enthält ein String ein oder mehrere #13 Zeichen, liefert Getstring bei jedem Aufruf nur den Teilstring bis zum nächsten #13. Sind keine daten zum abholen bereit, liefert Getstring den Leerstring zurück, desgleichen wenn das erste Zeichen im Puffer #13 ist.
Deshalb sollte vor dem Aufruf von GetString mit Hilfe der Funktion DatenDa überprüft werden, ob es überhaupt etwas zum Abholen gibt.


Jetzt wünsch ich noch viel Spass bei der Verwendung der beiden Klassen.

omata 9. Mai 2010 21:53

Re: Klassen für einfache IPC (InterProzessCommunication)
 
Dann eben nicht...

idefix2 9. Mai 2010 23:30

Re: Klassen für einfache IPC (InterProzessCommunication)
 
Hmm, ein nettes Programm, und sicher auch sehr brauchbar, wenn man die Kommunikation in einem 2. Thread ablaufen lassen will. Hat aber nicht mehr viel mit dem gemeinsam, was ich im Sinn hatte: nämlich zwei möglichst einfach und flexibel zu verwendende, gegebenenfalls auch leicht erweiterbare Units (z.B. hinsichtlich anderer Datentypen) für IPC zu schreiben. Durch die Callback Routine - die Frequenz sollte eigentlich vom Aufrufer einstellbar sein - ist man diesbezüglich wahrscheinlich eingeschränkter, jedenfalls sind Anpassungen nicht mehr so einfach zu machen. Durch die Organisation mit Thread und Callback-Funktion wird dem Benutzer der Unit eine starrere Anwendungsstruktur aufgezwungen (oder er muss die Daten in der Callback Routine extra puffern, und wieder eigene Prozeduren zum Abholen der Daten schreiben), als wenn die Daten einfach mit GetString, oder in weiterer Folge mit GetByte, GetReal oder überhaupt GetMyRecord abgeholt werden können, wann und WIE immer es günstig erscheint - vorausgesetzt, der Puffer ist ausreichend dimensioniert.

Ich würde meinen, es wäre besser, den Thread als separate Klasse zu programmieren, der ihrerseits die ursprüngliche IPCClient Klasse verwendet, um die Daten abzuholen. Damit stünde die Threadfunktionalität zusätzlich zu den Möglichkeiten der Originalklasse zur Verfügung, die ja auch völlig asynchron verwendet werden kann.

Den Sinn einiger Deiner Änderungen habe ich nicht verstanden, z.B. wozu Du eine protected und eine public isData Funktion samt Rekursion eingeführt hast, die gemeinsam nicht mehr tun als der ursprüngliche 5-Zeiler, und wozu Du den Type Buffer in einer eigenen Unit veröffentlichst - Ich habe ihn bewusst in den protected Bereich der beiden Klassen gelegt, weil die interne Struktur für den, der die Klassen verwendet, nicht relevant ist und ich sie deshalb eben nicht öffentlich haben wollte. Natürlich muss bei einer Änderung der Struktur in beiden Units diese Änderung parallel gemacht werden, aber nachdem bei einer solchen Änderung ohnedies auch der Programmcode in beiden Units entsprechend angepasst werden müsste, ist das ziemlich egal.

{$R-} ist die Delphi Defaulteinstellung, man sollte das vielleicht zur Sicherheit zusätzlich an den Anfang der beiden Units setzen. Nach den kritischen Stellen, wo eine Bereichsprüfung eine Exception auslösen würde, für den ganzen weiteren Code die Bereichsprüfung - entgegen den Delphi Defaulteinstellungen - einzuschalten, halte ich nicht für eine gute Idee - obwohl es zumindest beim aktuellen Code ziemlich egal ist, weil dort, glaube ich, keine Bereichsprüfungen mehr in Frage kommen. Aber andere Units übersetzt Du ja normalerweise auch nicht mit {$R+}, oder?

omata 9. Mai 2010 23:43

Re: Klassen für einfache IPC (InterProzessCommunication)
 
Und noch ein Kommentar: Man merkt, du hast gar keine Anhnung, was ich da eigentlich gemacht habe. Aber das ist ja auch egal.

wine 10. Mai 2010 01:54

Re: Klassen für einfache IPC (InterProzessCommunication)
 
Hatte mir den von Omata überarbeiteten SourceCode mit Beispiel aus #2 heruntergeladen, habe ihn mir aber noch nicht angesehen. Aber "mit Beispiel" klingt immer ganz gut :-)

Der eine hat Dephi 7 Enterprise, der andere RAD-Studio 2009 Pro?

Zickenkrieg in OpenSource wegen falscher Schuhgrösse oder was?

Gegenseitige Beleidigungen werden NIEMANDEM weiterhelfen...

Ruhig Brauner, brrrrrr, ruhig ;-)

wine

idefix2 10. Mai 2010 07:02

Re: Klassen für einfache IPC (InterProzessCommunication)
 
Es tut mir leid, dass ich Dich offensichtlich schwerstens beleidigt habe, was überhaupt nicht meine Absicht war.

Der Ansatz, den Datenempfang im Hintergrund in einem Extrathread zu automatisieren, ist zweifellos für viele Situationen ein sehr guter. Ich würde meinen, dass die von Dir programmierte Threadklasse eine feine Ergänzung des TIPCClient wäre, ich würde sie aber nicht als Ersatz sehen, weil es auch Situationen gibt, in denen man eine Kommunikation im Hintergrund nicht braucht oder nicht will.

Optimal wäre meiner Meinung nach eine zusätzliche Klasse TIPCThread, die ihrerseits TIPCClient zum Abholen der Daten verwendet.

Es tut mir leid, dass das offenbar ganz anders hinübergekommen ist.

Die Frage nach der Motivation für die Änderungen, die ich nicht verstanden habe, war genau so gemeint, wie ich es geschrieben habe - ich verstehe es wirklich nicht und würde es gerne wissen.

spaxxn 10. Mai 2010 07:42

Re: Klassen für einfache IPC (InterProzessCommunication)
 
Gibt ja zum Glück Interfaces und Vererbung :)


Alle Zeitangaben in WEZ +1. Es ist jetzt 17:17 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz