Erste Kontaktaufnahme (Basisprogramm für die Socket-Programmierung)

Dieses erste Programmbeispiel beschreibt die grundlegenden Techniken der Socket-Programmierung unter Verwendung der beiden Delphi-Klassen TServerSocket und TClientSocket.

Client-Server-Anwendungen verwenden in der Regel unterschiedliche Rechner für das Server- und das Client-Programm. Für diesen ersten Zugriff (Programm Kontakt1) verwendet das Programm zugleich einen Serversocket und einen Clientsocket, repräsentiert durch zwei verschiedene Fenster. Man kann damit beide Aspekte der Client-Server Kommunikation in einem Programm  erfahren und ausprobieren.

Das Programm verwendet als IP Adresse die symbolische Adresse 'Localhost' (= 127.0.0.1) und den Port 8181 für den Serversocket.


Projektbeschreibung



Das Programm Kontakt1 beschreibt und demonstriert die grundlegenden Techniken der Kontaktaufnahme von einem Client mit einem Server und die Kommunikation dieser beiden Sockets. Das Programm enthält neben dem Hauptfenster hierzu zwei weitere Fenster, die als Server- und als Client-Prozess arbeiten. Demzufolge besitzen diese Fenster jeweils eine Serversocket- bzw. eine Clientsocket-Komponente, dazu weitere Steuerelemente.

Sprechweise: Wir sprechen im Weiteren etwas unpräzise, aber vereinfachend von einem Server (bzw. Client), und identifizieren den Server-Rechner mit dem Server-Programm und mit seinem Serversocket.

Das Server-Fenster

Das Server-Programm enthält eine Schaltfläche um den Serversocket zu starten oder zu stoppen., ferner ein Memo-Feld, um den Status der Kommunikation anzuzeigen, und natürlich eine Serversocket-Komponente.


Die Namen der Komponenten:

Name
Komponente
FrmServer Formular
ServerSocket Serversocket-Komponente
BtStartStop Schaltfläche
MemStatus Memo-Feld


Vorbereitungen des Servers

Damit sich ein Client mit dem Server verbinden kann, muss dieser vorher
Port = 8181   Der Port ist hier mit 8181 voreingestellt.
Host = Localhost  oder
Host = 127.0.0.1
Als IP Adresse verwendet eine Serversocket-Komponente die des aktuellen Rechners.
 

Eigenschaft Socket

Socket-Komponenten besitzen die Eigenschaft Socket. Diese existiert nur zur Laufzeit des Programms und wird daher nicht im Objektinspektor angezeigt. Die Eigenschaft Socket kapselt Socket-Objekte, die die Funktionalität eines Sockets aus dem WinSock-API bereitstellen. Daher sind unter dieser Eigenschaft weitere Eigenschaften und Methoden vorhanden, insbesondere die zum Start eines Sockets.

Öffnen und Schließen eines  Sockets

mittels Methode:
ServerSocket.Open
ServerSocket.Close
oder mittels Eigenschaft:
ServerSocket.Active := True
ServerSocket.Active := False
   

Die Ereignismethode der Schaltfläche BtStartStop, die den Server öffnet oder schließt, demonstriert die Verwendung der oben beschriebenen Eigenschaften und Methoden.

procedure TFrmServer.BtStartStopClick (Sender: TObject);
begin
  if ServerSocket.Active
    then begin
      ServerSocket.Active := False;
     
// ServerSocket.Close;
      BtStartStop.Caption := 'Server Start';
      MemStatus.Lines.Add ('Status: Server angehalten')
    end
    else begin
      ServerSocket.Active := True;
      // ServerSocket.Open;
      ServerAktiv := True;
      BtStartStop.Caption := 'Server Stop';
      MemStatus.Lines.Add ('Status: Server gestartet')
    end
end;


Server aktiv?
ja: Server anhalten
geht auch



nein: Server starten
geht auch


Das Client-Fenster

Das Client-Fenster hat die gleiche Struktur wie das Server-Fenster: Mithilfe der Schaltfläche BtVerbinden kann sich der Client mit dem Serversocket verbinden und diese Verbindung wieder trennen. Der Status des Clients wird im Memo-Feld protokolliert.



Die Fensterkomponente verwendet das Attribut Verbunden: Boolean für die interne Verwaltung des Zustandes der Verbindung.
Die Namen der verwendeten Komponenten:

Name Komponente
FrmClient   Formular
Verbunden: Boolean; (interne) Zustandsvariable
ClientSocket Clientsocket-Komponente
BtVerbinden Schaltfläche
MemStatus Memo-Feld


Verbinden mit dem Serversocket

Bevor ein Clientsocket aktiviert werden kann, muss er mit der IP Adresse und dem Port des Serversockets initialisiert werden, bei dem er sich anmelden möchte. Initialisiert wird entweder mithilfe des Objektinspektor zur Entwicklungszeit des Programms (siehe oben Grafik) oder zur Laufzeit mittels Wertzuweisung (siehe unten Programmbeispiel). Die Ereignismethode der Schaltfläche BtVerbinden demonstriert das Verbinden des Clients mit einem Server und das Trennen dieser Verbindung.

procedure TFrmClient.BtVerbindenClick(Sender: TObject);
begin
   if Verbunden
     then begin
       ClientSocket.Close;
      
Verbunden := False;
       BtVerbinden.Caption := 'Mit Server verbinden';
     end
     else begin
       ClientSocket.Host := Adresse;
       ClientSocket.Port := Port;
       ClientSocket.Open;   
   
      
Verbunden := True;
       BtVerbinden.Caption := 'Vom Server trennen';
     end
end;


Mit Server verbunden?
ja: Verbindung trennen



nein: Verbindung herstellen
 



Fehlermeldungen

Lässt sich eine der oben beschriebenen Socket-Operationen nicht ausführen, tritt also ein Verbindungsfehler auf, so wird für die betroffene Socket-Komponente das Ereignis OnError ausgelöst und das Programm mit einem entsprechenden Error-Code unterbrochen.

Typisches Beispiel:  Der Client versucht sich mit dem nicht geöffneten Server zu verbinden (Fehlermeldung 100061)



Man kann diese Programmunterbrechung unterbinden, indem man diese Fehlermeldungen in der zum Ereignis OnError gehörenden Ereignismethode bearbeitet und abschließend den Error-Code auf  0 zurücksetzt. Da diese Ereignismethode vor der Error-Behandlung des Delphi-Systems bearbeitet wird, wird hierdurch ein solcher Programmabbruch verhindert.

procedure TFrmClient.ClientSocketError (Sender: TObject; Socket: TCustomWinSocket;
                                        ErrorEvent: TErrorEvent; var ErrorCode: Integer);
begin
  MemStatus.Lines.Add ('Status: Fehler ' + IntToStr(ErrorCode));
   ...
  ErrorCode := 0;
end;


Eventuell weitere Reaktionen auf
den Fehler
Verhindert eine Fehlermeldung des Systems
 

Weitere Ereignisse

Auch während der einzelnen Aktionen zwischen Client und Server (Verbinden, Trennen, Datenaustausch) werden Delphi-typisch zahlreiche Ereignisse ausgelöst.

Wichtige Ereignisse des Client-Socket-Komponente

Ereignis
Das Ereignis tritt ein
OnConnect
unmittelbar vor dem Öffnen der Verbindung zu Serversocket
OnRead
wenn ein Clientsocket Informationen aus der Socketverbindung lesen soll
OnWrite
wenn ein Clientsocket Informationen in die Socketverbindung schreiben soll
OnDisconnect
vor dem Schließen der Verbindung zu einem Servesocket
OnError
wenn ein Socket eine Verbindung nicht erstellen, verwenden oder schließen kann


Wichtige Ereignisse des Serversocket-Komponente

Ereignis
Das Ereignis tritt ein
OnAccept unmittelbar nach dem Akzeptieren der Verbindung mit einem Clientsocket
OnClientConnect wenn ein Clientsocket eine vom Serversocket akzeptierte Verbindung einrichtet
OnClientRead wenn der Serversocket Informationen aus dem Clientsocket lesen muss
OnClientWrite wenn der Serversocket Informationen in einen Clientsocket schreiben muss
OnClientDisconnect wenn eine der Verbindungen zu einem Clientsocket geschlossen wird
OnClientError wenn beim Einrichten, Verwenden oder Beenden der Socketverbindung zu einem Clientsocket ein Fehler auftritt


Beispiel

Bei der Aktivierung eines Clientsockets werden die den Ereignisse zugeordneten Ereignis-Methoden in dieser Abfolge ausgeführt:


// Zustand: Clientsocket inaktiv
procedure TFrmClient.ClientSocketConnecting (Sender: TObject; Socket: TCustomWinSocket);
begin
  MemStatus.Lines.Add ('Status: Verbindung wird aufgebaut');
end;

procedure TFrmClient.ClientSocketConnect (Sender: TObject; Socket: TCustomWinSocket);
begin
  MemStatus.Lines.Add ('Status: Verbindung hergestellt');
end;
// Zustand: Clientsocket aktiv (mit einem Serversocket verbunden)
// Mögliche Ereignisse:
procedure TFrmClient.ClientSocketRead (Sender: TObject; Socket: TCustomWinSocket);
begin
    ...
end;

procedure TFrmClient.ClientSocketWrite (Sender: TObject; Socket: TCustomWinSocket);
begin
    ...
end;

procedure TFrmClient.ClientSocketError (Sender: TObject; Socket: TCustomWinSocket;
                                         ErrorEvent: TErroeEvent; var ErrorCode: Integer);
begin
  MemStatus.Lines.Add ('Status: Fehler ' + IntToStr(ErrorCode));
  ErrorCode := 0
end;

procedure TFrmClient.ClientSocketDisconnect (Sender: TObject; Socket: TCustomWinSocket);
begin
  MemStatus.Lines.Add ('Status: Verbindung wird getrennt');
end;
// Zustand: Clientsocket inaktiv


Analog einige Ereignis-Methoden des Serversockets

// Zustand:  Server aktiv

procedure TFrmServer.ServerSocketAccept (Sender: TObject; Socket: TCustomWinSocket);
begin
  MemStatus.Lines.Add ('Status: Client verbunden');
  Socket.SendText ('Willkommen, Client ... ')
end;

procedure TFrmServer.ServerSocketClientConnect(Sender: TObject; Socket: TCustomWinSocket);
begin
  MemStatus.Lines.Add ('Status: Client verbunden');
  Socket.SendText ('Willkommen, Client ... ')
end;

procedure TFrmServer.ServerSocketClientRead (Sender: TObject; Socket: TCustomWinSocket);
begin
  MemStatus.Lines.Add (Socket.ReceiveText);
  Socket.SendText ('Hallo, Peter ...');
end;

procedure TFrmClient.ClientSocketError (Sender: TObject; Socket: TCustomWinSocket;
                                         ErrorEvent: TErroeEvent; var ErrorCode: Integer);
begin
  MemStatus.Lines.Add ('Status: Fehler ' + IntToStr(ErrorCode));
  ErrorCode := 0
end;
procedure TFrmServer.ServerSocketClientDisconnect(Sender: TObject; Socket: TCustomWinSocket);
begin
  MemStatus.Lines.Add ('Status: Client abgemeldet');
  Socket.SendText ('Tschüss, Client ... ')
end;

Wird das Programm Kontakt1 um diese Ereignis-Methoden ergänzt, ergeben sich für die beiden Fenster die weiter oben abgebildeten Ausgabe in den Memo-Feldern.

  Download Programm Kontakt1  (Delphi 7):  Kontakt1.zip


Exkurs: Server und Client auf zwei Rechnern

Das vorige und die folgenden Programmierbeispiele sind so angelegt, dass der Serversocket und der Clientsocket im gleichen Programm auf demselben Rechner laufen. Das vereinfacht hier die Programmentwicklung und ermöglicht die Demonstration der Zusammenhänge auf einem einzigen Rechner. Tatsächlich laufen Server- und Client-Programm üblicherweise auf verschiedenen Rechnern.

Zur Demonstration dieses Sachverhaltes dient das Programm Kontakt2. Es besteht aus den beiden Programmen Server2 und Client2, die auf verschiedenen Rechnern gestartet werden können. Im Gegensatz zum vorigen Programm muss der Clientsocket dann noch an die IP Adresse und die Portnummer des Server-Sockets angepasst werden. Das Fenster des Client-Programms hat hierfür zusätzliche Eingabefelder EdAdresse und EdPort.

  Download Programm Kontakt2  (Delphi 7):  Kontakt2.zip

Alle noch folgenden Programmbeispiele können - und sollten - in gleicher Weise zu "echten" Client-Server-Anwendungen erweitert werden.

        


(FvSG 30.1.2006)