Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Netzwerke (https://www.delphipraxis.net/14-netzwerke/)
-   -   IdTCPServer/IdTCPClient: Verbindung ablehnen? (https://www.delphipraxis.net/174513-idtcpserver-idtcpclient-verbindung-ablehnen.html)

romber 26. Apr 2013 12:39

IdTCPServer/IdTCPClient: Verbindung ablehnen?
 
Hallo!

Ich habe ein TCP-Server auf Basis von Indy TIdTCPServer. Wenn sich ein Client versucht, mit dem Server zu verbinden, erwartet der Server bestimmte Daten von ihm. Diese Daten werte ich im OnConnect des Servers aus. Werden keine bzw. falsche Daten übertragen, soll die Verbindung sofort beendet werden.

Wie kann ich im OnConnect prüfen, ob der Client beim Verbinden irgendwelche Daten gesendet hat? Wenn ich versuche, die Daten zu empfangen, die gar nicht gesendet wurden, dann bleibt die Verbindung an dieser stelle hängen, bis der Client etwas sendet bzw. ein Timeout ausgelöst wird.

Delphi-Quellcode:
ConnectMessage := AContext.Connection.IOHandler.ReadLn(TEncoding.UTF8);
Kann ich davor prüfen, ob der Client etwas gesendet hat und bei bedarf die Verbindung sofort beenden?

sx2008 26. Apr 2013 13:12

AW: IdTCPServer/IdTCPClient: Verbindung ablehnen?
 
Soo geht das nicht.
Wenn der Client sich mit dem Server verbindet, dann zwingt ihn niemand sofort Daten zu senden.

Dein Server braucht für jede Verbindung ein Kontext-Objekt, in dem der Zustand der Verbindung gespeichert wird.
Delphi-Quellcode:
TKontext = class(TObject)

public
  Username:string;
  LoggedIn : Boolean;
  ConnectionTime : TDateTime;
  ...
end;
Wenn der Client etwas sendet, dann kann der Server z.B. prüfen, ob sich der Client schon angemeldet hat.
Du bist etwas unpräzise mit deiner Aussage "erwartet der Server bestimmte Daten von ihm".
Deshalb nehme ich hier mal an, dass der Client sich mit User und Passwort anmelden soll.

Auf jeden Fall kannst du die Anmeldung nicht im OnConnect abfrühstücken.
Im OnConnect kannst du nur das Kontext-Objekt erzeugen; alles andere kommt später.

romber 26. Apr 2013 15:17

AW: IdTCPServer/IdTCPClient: Verbindung ablehnen?
 
Danke für die schnelle Reaktion!

Zitat:

Zitat von sx2008 (Beitrag 1213012)
Wenn der Client etwas sendet, dann kann der Server z.B. prüfen, ob sich der Client schon angemeldet hat.
Du bist etwas unpräzise mit deiner Aussage "erwartet der Server bestimmte Daten von ihm".
Deshalb nehme ich hier mal an, dass der Client sich mit User und Passwort anmelden soll.

So ist es. Der Server erwartet die Zugangsdaten in einem bestimmten Format. Ist die Anmeldung erfolgreich, schickt der Klient überhaupt keine Daten mehr, der enpfängt nur die Daten vom Server.

Zitat:

Zitat von sx2008 (Beitrag 1213012)
Auf jeden Fall kannst du die Anmeldung nicht im OnConnect abfrühstücken. Im OnConnect kannst du nur das Kontext-Objekt erzeugen; alles andere kommt später.

Der Objekt wir bei mir im OnConnect erzeugt, allerdings erst nach dem die Zugangsdaten geprüft und der Zugang genehmigt wurde. Dafür ist auch noch eine Datenbankabfrage notwendig. Wenn ich jetzt so überlege, ich kann das doch im OnExecute machen, bevor der Server begint, die Daten zu schicken. Oder wo macht man solche Prüfungen am besten?

sx2008 26. Apr 2013 19:39

AW: IdTCPServer/IdTCPClient: Verbindung ablehnen?
 
Zitat:

Zitat von romber (Beitrag 1213038)
Der Objekt wir bei mir im OnConnect erzeugt, allerdings erst nach dem die Zugangsdaten geprüft und der Zugang genehmigt wurde.

Das würde ich ändern und das Objekt gleich erzeugen.
Ein Boolean Flag gibt an, ob der Client sich schon erfolgreich angemeldet hat.
Im OnConnect kann der Server z.B. eine Willkommensnachricht an den Client schicken aber es ist nicht der richtige Ort um schon durch die Anmeldung zu gehen.

Hier ein Beispiel für die Komunikation
Code:
Client öffnet die TCP-IP Connection
Server -> Client: "App-Server Version x.x"#13#10 (wird noch im OnConnect gesendet)
Client -> Server: "LOGIN username, passwort"#13#10
Server -> Client: "LOGIN OK"#13#10   oder "ACCESS DENIED"#13#10 (reaktion des Servers in OnExecute)
Server -> Client: "TEMP 25.5"#13#10  (das sind die Daten die der Server schickt, aber nur wenn der Benutzer angemeldet ist)
Server -> Client: "......."#13#10
Client -> Server: "LOGOFF"#13#10   (Client meldet sich ab)
Server schliest die TCP-IP Connection

romber 27. Apr 2013 11:24

AW: IdTCPServer/IdTCPClient: Verbindung ablehnen?
 
Zitat:

Zitat von sx2008 (Beitrag 1213077)
Client -> Server: "LOGIN username, passwort"#13#10

Und wenn der Client nichts sendet, nachdem er sich Verbunden hat? Wie breche ich die Verbindung ab, wenn der Client nichts sendet?

mjustin 27. Apr 2013 11:48

AW: IdTCPServer/IdTCPClient: Verbindung ablehnen?
 
Zitat:

Zitat von romber (Beitrag 1213131)
Zitat:

Zitat von sx2008 (Beitrag 1213077)
Client -> Server: "LOGIN username, passwort"#13#10

Und wenn der Client nichts sendet, nachdem er sich Verbunden hat? Wie breche ich die Verbindung ab, wenn der Client nichts sendet?

Nach dem Verbindungsaufbau wird von Indy "sofort" die OnExecute Methode aufgerufen.

In dieser würde ich auch die erste Aktion des Servers unterbringen, das Warten auf die erste Nachricht (zum Beispiel Login).

Also in etwa (ungetestet):

Delphi-Quellcode:
procedure TMyIdTCPServer.OnExecute(AContext: TIdContext);
var
  Msg: string;
begin
  if not TMyContext(AContext).LoggedIn then
  begin
    // warte maximal 2000 Millisekunden
    Msg := AContext.Connection.IOHandler.ReadLn(2000);
    // Zeitüberschreitung?
    if AContext.Connection.IOHandler.ReadLnTimedOut then
    begin
      // lasse Indy die Connection beenden
      raise EIdException.Create('Received no login message');
    end else begin
      // prüfe, ob Login gültig und setze AContext.LoggedIn
      ...
    end;
  end
  else
  begin
    // bereits angemeldet, andere Aktionen ausführen
  end;
end;
AContext ist dabei eine anwendungsspezifische Unterklasse von TIdServerContext, in der die Property IsLoggedIn enthalten ist.

romber 27. Apr 2013 17:15

AW: IdTCPServer/IdTCPClient: Verbindung ablehnen?
 
Eins kapiere ich nocht nicht ganz. :oops:

Zitat:

Zitat von mjustin (Beitrag 1213135)
Delphi-Quellcode:
procedure TMyIdTCPServer.OnExecute(AContext: TIdContext);
var
  Msg: string;
begin
  if not TMyContext(AContext).LoggedIn then
  begin
    // warte maximal 2000 Millisekunden
    Msg := AContext.Connection.IOHandler.ReadLn(2000);
    // Zeitüberschreitung?
    if AContext.Connection.IOHandler.ReadLnTimedOut then
    begin
      // lasse Indy die Connection beenden
      raise EIdException.Create('Received no login message');
    end else begin
      // prüfe, ob Login gültig und setze AContext.LoggedIn
      ...
    end;
  end
  else
  begin
    // bereits angemeldet, andere Aktionen ausführen
  end;
end;

Und zwar nehmen wir an, der Client ist LoggedIn und dann bricht die Verbindung plötzlich ab, warum auch immer. Dann ist der AContext, mit dem im o.g. Beispiel TMyContext identifiziert wird, nicht mehr gültig oder verstehe ich das falsch? Der Client stellt die Verbindung wieder her und bekommt einen neuen AContext zugewiesen. Wenn das so ist, wofür dann die
Delphi-Quellcode:
if not TMyContext(AContext).LoggedIn
? Natürlich kann ich hinter LoggenIn-Property eine Funktion bauen, die überprüft, ob der Client bereits eingeloggt ist. Dafür benotige ich aber wiederum die Login-Daten des Clients, die erst in
Delphi-Quellcode:
Msg := AContext.Connection.IOHandler.ReadLn(2000)
abgefragt werden.


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

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