Kommunikation via named pipes

Für alles, was in den übrigen Lazarusthemen keinen Platz, aber mit Lazarus zutun hat.
Antworten
braunbär
Beiträge: 463
Registriert: Do 8. Jun 2017, 18:21
OS, Lazarus, FPC: Windows 10 64bit, Lazarus 3.6, FPC 3.2.2
CPU-Target: 64Bit
Wohnort: Wien

Kommunikation via named pipes

Beitrag von braunbär »

Hi!

Nachdem für mein aktuelles projekt eine Kommunikation zwischen zwei Prozessen erforderlich ist, bin ich über "named pipes" gestolpert. Das ist vermutlich die beste Methode, Daten zwischen den Programmen auszutauschen.

Jetzt bastle ich schon eine ganze Weile an einem einfachen Testprogramm, aber ich komme auf keinen grünen Zweig.

Das ist der Server:

Code: Alles auswählen

program pipeserver;

uses
  Windows, SysUtils;

const
  PIPE_ACCESS_DUPLEX = 3;
  PIPE_TYPE_MESSAGE = 4;
  PIPE_READMODE_MESSAGE = 2;
  PIPE_WAIT = 0;

  PIPE_NAME = '\\.\pipe\MDB';
  BUFSIZE = 128;

var
  hPipe: THandle;
  geschrieben, gelesen: DWORD;
  msg: string[127];

procedure fehler(const s: string);
begin
  raise Exception.Create('Fehler ' + IntToStr(getlasterror) + ' ' + s) ;
end;


begin
  try
    // Pipe erstellen
    hPipe := CreateNamedPipe(PIPE_NAME, PIPE_ACCESS_DUPLEX,
                             PIPE_TYPE_MESSAGE or PIPE_READMODE_MESSAGE or PIPE_WAIT,
                             1, BUFSIZE, BUFSIZE, 0, nil);

    if hPipe = INVALID_HANDLE_VALUE
    then fehler('Fehler beim Erstellen der Pipe');

    // Warte auf eine Verbindung des Clients
    WriteLn('Warte auf Client...');
    if not ConnectNamedPipe(hPipe, nil)
    then begin
         Write('Client Verbindung klappt nicht.');  readln;
         fehler('beim Verbinden');
         end;

    // Lese die Nachricht des Clients
    writeln ('Lese Nachricht');
    if not ReadFile(hPipe, msg, BUFSIZE, gelesen, nil)
    then fehler('beim Lesen');

    // Nachricht des Clients ausgeben
    WriteLn('Nachricht vom Client: ', msg);

    // Sende Antwort zurück an den Client
    msg := 'Server Antwort: ' + msg;
    if not WriteFile(hPipe, msg, Length(msg)+1, geschrieben, nil)
    then fehler('beim Schreiben');

    WriteLn('Gesendet: ', msg);

    // Schließe die Pipe
    CloseHandle(hPipe);

  except
    on E: Exception do begin WriteLn(E.Message); readln end;
  end;
end.
und das der Client:

Code: Alles auswählen

program pipeclient;

uses
  Windows, SysUtils;

const
  PIPE_NAME = '\\.\pipe\MDB';
  BUFSIZE = 128;

var
  hPipe: THandle;
  geschrieben, gelesen: DWORD;
  msg: string[127];

procedure fehler(const s: string);
begin
  raise Exception.Create('Fehler ' + IntToStr(getlasterror) + ' ' + s) ;
end;



begin
  write('Client gestartet - Enter drücken'); readln;
  try
    // Pipe öffnen
    hPipe := CreateFile(PIPE_NAME, GENERIC_READ or GENERIC_WRITE,
                        0, nil, OPEN_EXISTING, 0, 0);

    if hPipe = INVALID_HANDLE_VALUE
    then fehler('beim Verbinden');

    WriteLn('Mit Server verbunden.');

    // Sende eine Nachricht an den Server
    write('Enter message: '); readln(msg);
    if not WriteFile(hPipe, msg, Length(msg)+1, geschrieben, nil)
    then fehler('beim Schreiben');

    WriteLn('Nachricht an den Server gesendet: ', msg);

    // Lese die Antwort des Servers
    if not ReadFile(hPipe, msg, BUFSIZE, gelesen, nil)
    then fehler('beim Lesen');

    // Ausgabe der Antwort des Servers
    WriteLn('Empfangen: ', msg);

    // Schließe die Pipe
    CloseHandle(hPipe);

  except
    on E: Exception do begin WriteLn('Fehler: ', E.Message); readln end;
  end;
end.
Serverseitig scheint das Erstellen der Pipe zu funktionieren, Clientseitig geht es bis zur Verbindung gut.
Aber sobald der Client eine Nachricht an den Server absetzt (writefile Zeile 36) schließen sich BEIDE Konsolenfenster kommentarlos. Nicht einmal die Exceptions kommen zum Tragen, es gibt weder beim Serverprogramm noch beim Clientprogramm irgendeine Meldung.
Zuletzt geändert von braunbär am Mo 30. Dez 2024, 15:00, insgesamt 1-mal geändert.

Benutzeravatar
theo
Beiträge: 10856
Registriert: Mo 11. Sep 2006, 19:01

Re: Kommunikation via named pipes

Beitrag von theo »

Schon mal mit SimpleIPC versucht? (Tab: System).

https://www.freepascal.org/docs-html/cu ... index.html

braunbär
Beiträge: 463
Registriert: Do 8. Jun 2017, 18:21
OS, Lazarus, FPC: Windows 10 64bit, Lazarus 3.6, FPC 3.2.2
CPU-Target: 64Bit
Wohnort: Wien

Re: Kommunikation via named pipes

Beitrag von braunbär »

Nein, aber eigentlich würde ich gerne das Programm so wie es ist zum Laufen bringen. Irgendein Parameter muss falsch sein, aber der Code ist so simpel.. Dass sogar beide Programme beim Senden der ersten Nachricht komplett abstürzen, erscheint mir ziemlich absurd.

Letztlich muss der Pipe Server unter Windows laufen, während ich die Pipe Clients unter Dos mit Turbo Pascal 6 programmieren muss. Da ist die Implementierung mit Hilfe solcher Klassen kontraproduktiv, weil ich das unter Turbo Pascal 6 wahrscheinlich erst wieder komplett umbauen müsste. Named Pipe clients sollten ja auch unter der DOS Oberfläche funktionieren.

Benutzeravatar
theo
Beiträge: 10856
Registriert: Mo 11. Sep 2006, 19:01

Re: Kommunikation via named pipes

Beitrag von theo »

Ich weiss nicht, auf welchem Level du bist.
Ich bin jedenfalls nicht auf Windows. Wenn ich die Doku zu WriteFile nachschlage, dann wird an zweiter Stelle ein LPCVOID erwartet.
Dort einfach einen String[127] zu übergeben ist wahrscheinlich falsch.
https://learn.microsoft.com/en-us/windo ... -writefile

Benutzeravatar
Jorg3000
Lazarusforum e. V.
Beiträge: 359
Registriert: So 10. Okt 2021, 10:24
OS, Lazarus, FPC: Win64
Wohnort: NRW

Re: Kommunikation via named pipes

Beitrag von Jorg3000 »

Hi!
Stell mal den msg: string[127] um auf Array[0..127] of Char.
Anstelle des Längen-Bytes an Index[0] sollte beim Senden ein NULL-Terminator #0 angehängt werden.

Server-seitig:

Code: Alles auswählen

program pipeserver;

uses
  Windows, SysUtils;

const
  PIPE_ACCESS_DUPLEX = 3;
  PIPE_TYPE_MESSAGE = 4;
  PIPE_READMODE_MESSAGE = 2;
  PIPE_WAIT = 0;

  PIPE_NAME = '\\.\pipe\MDB';
  BUFSIZE = 128;

var
  hPipe: THandle;
  geschrieben, gelesen: DWORD;
  msg: array[0..127] of Char;

procedure fehler(const s: string);
begin
  raise Exception.Create('Fehler ' + IntToStr(GetLastError) + ' ' + s);
end;

begin
  try
    hPipe := CreateNamedPipe(PIPE_NAME, PIPE_ACCESS_DUPLEX,
                             PIPE_TYPE_MESSAGE or PIPE_READMODE_MESSAGE or PIPE_WAIT,
                             1, BUFSIZE, BUFSIZE, 0, nil);

    if hPipe = INVALID_HANDLE_VALUE then
      fehler('Fehler beim Erstellen der Pipe');

    WriteLn('Warte auf Client...');
    if not ConnectNamedPipe(hPipe, nil) then
      fehler('Fehler beim Verbinden');

    WriteLn('Lese Nachricht...');
    if not ReadFile(hPipe, msg[0], BUFSIZE, gelesen, nil) then
      fehler('Fehler beim Lesen');

    WriteLn('Nachricht vom Client: ', msg);

    StrPCopy(msg, 'Server Antwort: ');
    if not WriteFile(hPipe, msg[0], StrLen(msg) + 1, geschrieben, nil) then
      fehler('Fehler beim Schreiben');

    WriteLn('Gesendet: ', msg);

    CloseHandle(hPipe);
  except
    on E: Exception do
      WriteLn(E.Message);
  end;
end.
Client-seitig:

Code: Alles auswählen

program pipeclient;

uses
  Windows, SysUtils;

const
  PIPE_NAME = '\\.\pipe\MDB';
  BUFSIZE = 128;

var
  hPipe: THandle;
  geschrieben, gelesen: DWORD;
  msg: array[0..127] of Char;

procedure fehler(const s: string);
begin
  raise Exception.Create('Fehler ' + IntToStr(GetLastError) + ' ' + s);
end;

begin
  WriteLn('Client gestartet - Enter drücken');
  ReadLn;
  try
    hPipe := CreateFile(PIPE_NAME, GENERIC_READ or GENERIC_WRITE,
                        0, nil, OPEN_EXISTING, 0, 0);

    if hPipe = INVALID_HANDLE_VALUE then
      fehler('Fehler beim Verbinden');

    WriteLn('Mit Server verbunden.');

    Write('Enter message: ');
    ReadLn(msg);
    if not WriteFile(hPipe, msg[0], StrLen(msg) + 1, geschrieben, nil) then
      fehler('Fehler beim Schreiben');

    WriteLn('Nachricht an den Server gesendet: ', msg);

    if not ReadFile(hPipe, msg[0], BUFSIZE, gelesen, nil) then
      fehler('Fehler beim Lesen');

    WriteLn('Empfangen: ', msg);

    CloseHandle(hPipe);
  except
    on E: Exception do
      WriteLn('Fehler: ', E.Message);
  end;
end.

braunbär
Beiträge: 463
Registriert: Do 8. Jun 2017, 18:21
OS, Lazarus, FPC: Windows 10 64bit, Lazarus 3.6, FPC 3.2.2
CPU-Target: 64Bit
Wohnort: Wien

Re: Kommunikation via named pipes

Beitrag von braunbär »

Danke für die Antworten.

Ich traue mich kaum, zu schreiben, was wirklich los war. Vielleicht gibt es ein Alter, an dem man das Programmieren aufgeben sollte...

Es hat alles von Anfang an einwandfrei funktioniert. Nachdem ich sowohl beim Client als auch beim Server nach dem Abschluss der Kommunikation das Programm sang- und klanglos beendet habe, ohne zumindest auf die Eingabe von "return" zu warten, sind die Fenster so schnell geschlossen worden, dass ich die Kontrollausgaben, die völlig richtig erfolgt sind, nicht mitbekommen habe...

So was kann zwar passieren, aber dann stundenlang nach einem Fehler suchen, den es nicht gibt, ist schon grenzwertig... :evil:

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6762
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Kommunikation via named pipes

Beitrag von af0815 »

Danke für die ehrliche Diagnose und ja, du bist kein Einzelfall :D Ist mir auch schon passiert, der Debugger mit Breakpoint auf die letzte Zeile hat mich schon öfters auf die richtige Fährte zurückgebracht.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Benutzeravatar
Jorg3000
Lazarusforum e. V.
Beiträge: 359
Registriert: So 10. Okt 2021, 10:24
OS, Lazarus, FPC: Win64
Wohnort: NRW

Re: Kommunikation via named pipes

Beitrag von Jorg3000 »

braunbär hat geschrieben: Mo 30. Dez 2024, 20:46 nach einem Fehler suchen, den es nicht gibt
Oh ja, ich weiß noch immer, was ich im Sommer 2019 gemacht habe.
Da habe ich mich bei schönstem Wetter eine Woche lang drinnen vorm PC eingeschlossen, um eine Fehlerursache zu finden. Habe mein ganzes Programm auf links gezogen. Habe in den tiefsten Untiefen meiner abhängigen Units alles auseinandergenommen und wieder neu zusammengesetzt. Habe Log-Dateien geschrieben und bin verzweifelt.
Nach einer kompletten Woche inkl. Wochenende bin ich dann darauf gekommen, dass ich auf oberster Ebene ein +1 vergessen habe (falscher Array-Index).

Alles funktionierte richtig, ich hatte mir bloß eine Woche lang die falschen Daten angeguckt. 8) Ich habe die ganze Tischkante zerbissen. Fataler Weise ähnelten die falschen den richtigen Daten so stark, dass es mir eine Woche lang nicht aufgefallen war.
Tja, das hartnäckigste Problem sitzt meistens vor dem Bildschirm. Es ist leider vertane Lebenszeit, die einem niemand zurückbringt. Krönchen richten, weitermachen. :P

charlytango
Beiträge: 1058
Registriert: Sa 12. Sep 2015, 12:10
OS, Lazarus, FPC: Laz stable (2.2.6, 3.x)
CPU-Target: Win 32/64, Linux64
Wohnort: Wien

Re: Kommunikation via named pipes

Beitrag von charlytango »

you made my day ;-)

Wenn auch Forenmitglieder, deren Expertise ich sehr schätze, mal zum Besten geben, dass sie auch mal den Wald vor lauter Bäumen nicht sehen und angesichts von Trivialfehlern einen Riesenaufwand brauchen um dann festzustellen dass dass man sich auch nicht in den Arsch beißen kann -- dann kann 2025 kaum mehr etwas schief gehen.

Danke, und..

Prosit 2025

braunbär
Beiträge: 463
Registriert: Do 8. Jun 2017, 18:21
OS, Lazarus, FPC: Windows 10 64bit, Lazarus 3.6, FPC 3.2.2
CPU-Target: 64Bit
Wohnort: Wien

Re: Kommunikation via named pipes

Beitrag von braunbär »

charlytango hat geschrieben: Mi 1. Jan 2025, 11:01 you made my day ;-)

Wenn auch Forenmitglieder, deren Expertise ich sehr schätze, mal zum Besten geben, dass sie auch mal den Wald vor lauter Bäumen nicht sehen und angesichts von Trivialfehlern einen Riesenaufwand brauchen um dann festzustellen dass dass man sich auch nicht in den Arsch beißen kann -- dann kann 2025 kaum mehr etwas schief gehen.

Danke, und..

Prosit 2025
Dem Prosit möchte ich mich ganz heftig anschließen :wink:

Benutzeravatar
Zvoni
Beiträge: 363
Registriert: Fr 5. Jul 2024, 08:26
OS, Lazarus, FPC: Windoof 10 Pro (Laz 2.2.2 FPC 3.2.2)
CPU-Target: 32Bit
Wohnort: BW

Re: Kommunikation via named pipes

Beitrag von Zvoni »

charlytango hat geschrieben: Mi 1. Jan 2025, 11:01 you made my day ;-)

Wenn auch Forenmitglieder, deren Expertise ich sehr schätze, mal zum Besten geben, dass sie auch mal den Wald vor lauter Bäumen nicht sehen und angesichts von Trivialfehlern einen Riesenaufwand brauchen um dann festzustellen dass dass man sich auch nicht in den Arsch beißen kann -- dann kann 2025 kaum mehr etwas schief gehen.

Danke, und..

Prosit 2025
Meine letzte grosse "Knalltüte" ist ca. 10 Jahre her.
Sollte bei mir in der Firma ein Tool in Excel/VBA schreiben (Automatisiertes Darstellen von SQL-Queries gegen unsere IBM DB2, inkl. setzen der Quelldaten für Diagramme aus dem Code).

Tja, hab ca. ne Woche gebraucht um herauszufinden, dass ich ein Semikolon mit nem Doppelpunkt verwechselt hatte (Tipp-Fehler!!).....
Ein System sie alle zu knechten, ein Code sie alle zu finden,
Eine IDE sie ins Dunkel zu treiben, und an das Framework ewig zu binden,
Im Lande Redmond, wo die Windows drohn.

Antworten