Einzelnen Beitrag anzeigen

Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.056 Beiträge
 
Delphi 12 Athens
 
#4

Re: Konzept gesucht - Interprocess communication

  Alt 18. Jan 2008, 23:54
(ich weiß, is schon ein bissl alt, aber Überschrift und Thema passen zu meinem Problem, also wozu einen neuen Thread aufmachen )

MMFs muß man ja nicht mit einer Datei verknüpfen und dann liegt nur eine virtuelle Datei im Arbeitsspeicher.

Wenn dann beide Prozesse beendet sind, dann wird der Speicher (also die Datei) freigegeben.


Aber für dein Problem ist es wohl wirklich am einfachsten sich Windowsnachrichten hin und eventuell zurückzuschicken.

A schickt alle 10 Sekunden eine Nachricht an B

und mißt die Zeit zur letzten empfangenen Nachricht ... z.B. 20-30 Sekunden keine Meldung von A, dann wird A neu gestartet.

> größere Zeit beim Prüfen, da Messages nicht unbedingt sofort ankommen und es mal mehr als 10 Sekunden dauern kann.






So, nun zu mir...

mein Programm hat schon eine IPC via WMs, aber nun bräuchteich noch eine bidirektionale Übertragung größerer Datenblöcke.

WM_COPYDATA geht ja nur zum Versenden und empfangen wirde bei der Implementierung wohl vollkommen ignoriert

also was wie Folgendes geht halt nicht.
Delphi-Quellcode:
X:Zeiger := ...;
X.MaxLen := 123456;
SendMessage(Wnd, WM_COPYDATA_RECIVE, @X, 0);

{ oder }

X := SendMessage(Wnd, WM_COPYDATA_RECIVE, 0, 0);
//X = sowas wie COPYDATASTRUCT
Eine nachricht al Anfrage zu senden und dann auf eine antwort z.B. per WM_COPYDATA zu warten ist auch nicht so optimal (Nachrichtenabarbeitungsreinfolge und Threadsicherheit würden da etwas leiden und müßten zusätzlich nochmals geprüft werden)

hab mich auch in letzter Zeit nach Com, ActiveX, Interfaces umgesehn, aber so richtig hab da noch icht durchgesehn

So wie Named-Pipes und Mail-Slots hat auch wieder andere Nachteile.

nunja und MMFs scheinen auch manchmal Probleme zu machen (z.B. kein Zugriff unter Vista u.a.)
Aber dennoch wollt ich's damit mal versuchen...

mein Code würde dann in etwa so aussehn:
- kleiner Testcode ohne (richtige) Fehlerbehandlung und Co.
- und noch nicht auf verschiedene Prozesse verteilt
das "Begin (* ... *)" bis "End;" stellt sozusagen jeweils den Messagehandler des Fremdprozesses dar
Delphi-Quellcode:
Const AllocSize = 64 * 1024; {diese größe wird dann auch noch dynamisch :wall: }

Var SourceMap, DestMap, H, S, R: THandle;
  Ps, Pd: Pointer{PAnsiChar};

Begin
  Try
    {MMF erstellen}
    SourceMap := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 0, AllocSize, nil);
    If SourceMap = INVALID_HANDLE_VALUE Then Exit;

    {was in die MMF reinschreiben ... zum Senden, falls nötig}
    Ps := MapViewOfFile(SourceMap, FILE_MAP_WRITE, 0, 0, 0);
    If Ps = nil Then Exit;
    // Copy(Ps, irgendwas)
    UnmapViewOfFile(Ps);

    {Handle der MMF für anderen Prozeß erstellen}
    {}If not DuplicateHandle(GetCurrentProcess, GetCurrentProcess, GetCurrentProcess, @H,
    {}  PROCESS_DUP_HANDLE, False, 0) Then Exit;
    //H := OpenProcess(PROCESS_DUP_HANDLE, False, GetCurrentProcessId);
    //If H = 0 Then Exit;
    S := SourceMap;
    Begin (* R := SendMessage(Wnd, WM_DUPLICATE_HANDLE, H, S); *)
      If not DuplicateHandle(H, S, GetCurrentProcess, @R,
        0, False, DUPLICATE_SAME_ACCESS) Then Exit;
    End;
    DestMap := R;

    {Nachricht senden}
    {und drüben die MMF auslesen/bearbeiten}
    H := DestMap;
    Begin (* R := SendMessage(Wnd, WM_MACHWAS, wmDiesUndDas, H); *)
      Pd := MapViewOfFile(H, FILE_MAP_READ{FILE_MAP_WRITE}, 0, 0, 0);
      If Pd = nil Then Exit;
      // Copy(Pd), oder so
      UnmapViewOfFile(Pd);
      CloseHandle(DestMap);
    End;

    {MMF auslesen ... zum Empfangen, falls nötig}
    Ps := MapViewOfFile(SourceMap, FILE_MAP_READ, 0, 0, 0);
    // Copy(irgendwas, Ps)
    UnmapViewOfFile(Ps);

    {MMF freigeben}
    CloseHandle(SourceMap);
  Finally
    Application.MessageBox(PChar(SysErrorMessage(GetLastError)), PChar(Caption));
  End;
End;
müßte doch so in etwa funktionieren ... denk ich mal.



nun ist mir dabei aber was aufgefallen ...

weil ich keine Names-MMFs verwenden kann (ein/zwei Günde nachfolgend) übergebe ich nun statt einen "Pointers auf die Daten" den Handle zur MMF.

... und da ich ja zur Handleübergabe das Prozeßhandle benötige, könnte ich doch eigentlich gleich statt PROCESS_DUP_HANDLE einfach PROCESS_VM_OPERATION+PROCESS_VM_READ+PROCESS_VM_WR ITE verwenden
und dann direkt via VirtualAllocEx+Read/WriteProcessMemory zugreifen?

unter Anderem könnte dann die angefragte Anwendung dann selber die Größe des Rückgabepuffers festlegen und ich müßte nicht vorher über eine zusätzliche Abfrage rausbekommen wieviel Speicher die MMF mindestens haben muß.


Gründe + grobe Programmstruktur:
- es gibt einen "Clienten", welcher von einem/mehreren "Servern" gesteuert wird, wobei die Server nicht wissen (müssen) das/ob es andere gibt.
- die Server können (müssen aber nicht) sich per WM beim Clienten anmelden und dort ein Handle und eine WM-ID hinterlegen, worüber sie eine Mitteilung bekommen, sobald sich was am Datenbestand durch irgendwen verändert hat.
- der Client steht immer auf Empfang und jeder Server kann ohne Voranmeldung senden
- es besteht aber die Möglichkeit zugriffe die Zur änderung der Daten im Clienten führen zu sperren (kann ein Server explizit beantragen, falls nötig)
- es können aber auch mehrere Clienten existieren (zwar sehr unwahrscheinlich, aber dennoch hab ich diese Möglichkeit offengelassen)

Dank der WM (SendMessage und Co) ist das ganze aber dennoch Threadsave, da schließlich immer nur eine WM zum selben Zeitpunkt verarbeitet wird,
was bei bidirektionaler Kommunikation per WM wiederum verlorengehen kann (drum kein WM_COPYDATA)

> Server sendet neue Daten oder fragt welche ab
> Client gibt bei Änderung über PostMessage (nur Integer und Co.) an registrierte Sever eine Meldung aus
= also keine gegenseitige Blockierung möglich


Mehrere Clienten/Server, darum keine Named-Pipes und Named-MMFs ... wie sollte ich da denn die Namen versenden, da ich ja grad zum Versenden/Empfangen von Namen und Dergleichen dieses benötige ...
wär ja so, als ließe ich das Huhn sein eigenes Ei legen lassen



Was meint ihr?
- die MMFs weiter ausbauen (hab's erstmal aufgehört und andere Möglichkeiten betrachtet, aber es ist schon was vorhanden)
- Direktzugriff (weniger Code = fehlerunanfälliger und dann auch noch ein einfacheres Speichermanagement)
oder habt ihr bessere Ideen?
- was ganz anderes (wenn ich Pech hab, darf ich da auch noch die gesamte Nachrichtenbehandlung und Programmstruktur ändern)


Ach ja, sollte die Kommunikation nur innerhalb des PCs (kein Netzwerk) und der selben Benutzerebene ablaufen ... jedenfalls fällt mir kein wirklcher Grund ein, warum beides/alles weiter auseinander sein sollte
und Vor-Win2000pro unterstütz ich auch nicht mehr explizit (also wenn es da nicht läuft ... egal )




Es gibt halt unzählige Möglichkeiten mit massig Vorteilen, aber wenn man die dann versucht auf ein bestimmtes Problem anzuwenden, dann hat alles irgendwie nur noch Nachteile
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.
  Mit Zitat antworten Zitat