Entwickler-Ecke

Internet / Netzwerk - Andere Programminstanzen der eigenen Anwendung im LAN finden


Narses - Di 08.05.12 13:58
Titel: Andere Programminstanzen der eigenen Anwendung im LAN finden
Wie kann man andere, laufende Instanzen der eigenen Anwendung im LAN finden?

Ein möglicher Ansatz ist eine Suche per UDP-Broadcast. Da nur im LAN gesucht werden soll (nicht im Internet oder WAN) sollte es keine Probleme mit einem UDP-Broadcast geben (diese werden häufig von Routern ausgefiltert). Für dieses Beispiel wird meine OpenSource-Komponente TUdpSockUtil [http://www.delphi-forum.de/topic_TUdpSockUtil+v201++Alternative+zum+IndyUDPClientServer_55339.html] verwendet.

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
uses
  ..., UdpSockUtil, WinSock; // WinSock wird für den Typ in_addr benötigt

const
  SERVICE_PORT   = 12345// hier wartet eine Instanz auf Anfragen
  MY_APP_REQUEST = AnsiString('FindLanInstanceDemo:Request');
  MY_APP_REPLY   = AnsiString('FindLanInstanceDemo:Reply');

// Beim Programmstart die Eigenschaften des UDP-Sockets setzen und öffnen
procedure TfrmMain.FormCreate(Sender: TObject);
begin
  UdpSockUtil1.LocalPort := SERVICE_PORT;
  UdpSockUtil1.RemotePort := SERVICE_PORT;
  UdpSockUtil1.Broadcast := TRUE;
  UdpSockUtil1.Open; // auf eingehende Pakete reagieren
end;

// Andere Instanzen per Rundesendenachricht im LAN suchen
procedure TfrmMain.btnSearchClick(Sender: TObject);
begin
  UdpSockUtil1.BroadcastText(MY_APP_REQUEST);
end;
Bis hier sind nur Voraussetzungen geschaffen worden. Kommen wir nun zum spannenden Teil, wo ein Datenpaket verarbeitet wird:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
// Es ist ein Datenpaket eingetroffen, untersuchen
procedure TfrmMain.UdpSockUtil1Receive(Sender: TObject);
  var
    SenderIP: in_addr;
    SenderPort: Integer;
    SenderData: AnsiString;
begin
  SenderData := UdpSockUtil1.ReceiveText(SenderIP, SenderPort); // Daten lesen
  if (SenderData = MY_APP_REQUEST) then begin
    // Anfrage nach laufender Instanz
    UdpSockUtil1.RemoteAddr := SenderIP; // an den Absender
    UdpSockUtil1.SendText(MY_APP_REPLY); // die Antwort senden
  end
  else if (SenderData = MY_APP_REPLY) then begin
    // Antwort auf Anfrage nach laufender Instanz
    SenderData := inet_ntoa(SenderIP); // IPddn -> String;
    if ListBox1.Items.IndexOf(SenderData) = -1 then // schon bekannt?
      ListBox1.Items.Add(SenderData); // nein, einfügen
  end
  else
    ShowMessage('Unbekanntes Datenpaket von '+inet_ntoa(SenderIP)+':'+IntToStr(SenderPort));
end;
Hier sind drei Fälle zu unterscheiden:
  1. Es wurde ein Anfrage-Paket empfangen (MY_APP_REQUEST)
    Eine andere Programminstanz (oder ggfs. auch die eigene, Broadcasts werden auch an sich selbst gesendet) fragt nach anderen im LAN. Antwortpaket (nur) an den Absender schicken, damit dieser diese Instanz erkennt.

  2. Es wurde ein Antwort-Paket empfangen (MY_APP_REPLY)
    Vorausgesetzt, wir hatten aus dieser Instanz angefragt, hat eine andere Instanz geantwortet. Absender registrieren :arrow: andere Instanz gefunden (ggfs. müsste man hier noch die eigene Instanz filtern, Ansatz: jede Instanz bei Programmstart eine GUID bilden lassen und diese mitsenden).

  3. Es wurde ein Datenpaket mit einem unbekannten Inhalt empfangen
    Fehler melden und ignorieren.
In Anhang befindet sich das komplette Demo-Projekt.

Hinweis: Da eine statische Service-Port-Zuordnung gemacht wird, kann man das Programm jeweils nur einmal pro Maschine starten. Für einen Test im LAN sind also mehrere PCs (oder VMs) nötig!