AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Netzwerke Delphi Indy TCP Client-Server Problem
Thema durchsuchen
Ansicht
Themen-Optionen

Indy TCP Client-Server Problem

Ein Thema von RedShakal · begonnen am 13. Jul 2009 · letzter Beitrag vom 14. Jul 2009
Antwort Antwort
RedShakal
(Gast)

n/a Beiträge
 
#1

Indy TCP Client-Server Problem

  Alt 13. Jul 2009, 22:14
Hallo mal wieder, ich habe vor kurzem vorgehabt für mein Programm ein Login Script zu schreiben. Irgentwann will ich die Daten mal in einer DB speichern aber zur zeit reicht erstmal ein Test Benutzername für meine Zwecke aus. Leider stecke ich bei der Kommunukation fest. Wenn Der Client was sendet, reagiert der Server nicht. Drückt man den Knopf nochmal bekommt man einen Fehler das die Verbindung bereits bestehen würde. Ich brauch mal eine zweite Person die über den Code drüberschaut und ggf. den Fehler findet


Die Login.pas
Delphi-Quellcode:
unit login;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, IniFiles, IdBaseComponent, IdComponent,
  IdTCPConnection, IdTCPClient;

type
  TForm1 = class(TForm)
    Username: TEdit;
    Label1: TLabel;
    Label2: TLabel;
    Passwort: TEdit;
    CheckBox1: TCheckBox;
    Button1: TButton;
    Button2: TButton;
    Client: TIdTCPClient;
    procedure Button2Click(Sender: TObject);
    procedure CheckBox1Click(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure ClientConnected(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

type
  TDynStringArray = array of string;

var
  Form1 : TForm1;
  Benutzername : string;

implementation

uses registration, main;

{$R *.dfm}

function Explode(const Separator, S :String; Limit :Integer = 0): TDynStringArray;
  var
    SepLen: Integer;
    F, P: PChar;
begin
  SetLength(Result, 0);
  if (S = '') or (Limit < 0) then
    Exit;
  if Separator = 'then
    begin
      SetLength(Result, 1);
      Result[0] := S;
      Exit;
    end;
  SepLen := Length(Separator);

  P := PChar(S);
  while P^ <> #0 do
    begin
      F := P;
      P := AnsiStrPos(P, PChar(Separator));
      if (P = nil) or ((Limit > 0) and (Length(Result) = Limit - 1)) then
        P := StrEnd(F);
      SetLength(Result, Length(Result) + 1);
      SetString(Result[High(Result)], F, P - F);
      F := P;
      if P = Separator then
        SetLength(Result, Length(Result) + 1);
      while (P^ <> #0) and (P - F < SepLen) do
        Inc(P);
    end;
end;


procedure TForm1.Button2Click(Sender: TObject);
begin
Form2.Visible := true;
Form1.Visible := false;
end;

procedure TForm1.CheckBox1Click(Sender: TObject);
var ini: TIniFile;
begin
  ini:=TIniFile.create(ExtractFilePath(ParamStr(0))+ 'settings.ini');

  if Checkbox1.Checked = true then
    begin
      ini.WriteBool('Login','Save',true);
      ini.WriteString('Login','Username',Username.Text);
      ini.WriteString('Login','Passwort',Passwort.Text);
    end
  else
    begin
      ini.WriteBool('Login','Save',false);
      ini.WriteString('Login','Username','');
      ini.WriteString('Login','Passwort','');
    end;
  ini.free;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Benutzername := Username.Text;
  Client.Connect(5000);
  Client.Write('Login' + '|' + Form1.Username.Text + '|' + Form1.Passwort.Text);
end;

procedure TForm1.FormCreate(Sender: TObject);
var ini: TIniFile;
begin
  ini:=TIniFile.create(ExtractFilePath(ParamStr(0))+ 'settings.ini');
  try
    Client.Host := ini.ReadString('Login','ServerIP','');
    Client.Port := ini.ReadInteger('Login','ServerPort',0);
    Username.Text := ini.ReadString('Login','Username','');
    Passwort.Text := ini.ReadString('Login','Passwort','');
    Checkbox1.Checked := ini.ReadBool('Login','Save',false);
  finally
    ini.free;
  end;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Form3.Chat.Disconnect();
  Form1.Client.Disconnect;
end;

procedure TForm1.ClientConnected(Sender: TObject);
var
  Buffer : String;
  StrArr : TDynStringArray;
begin

 Buffer := Client.ReadLn;

  if Length(Buffer) > 0 then
    begin
      StrArr := Explode('|', Buffer);
    end;

  if StrArr[0] = 'Connectedthen
    begin
      Form1.Visible := false;
      Form3.Visible := true;
      try
        Form3.Chat.Connect(3000);
        Form3.Chat.Nick := 'KKND|'+Benutzername;
        Form3.Chat.AltNick := 'KKND|'+Benutzername;
        Form3.Timer1.Enabled := true;
      except
        showmessage('Fehler beim Verbinden!');
      end;

  if StrArr[0] = 'Passwortthen
    begin
      showmessage('Benutzername und/oder Passwort falsch!');
      Client.Disconnect;
    end;
   end;
end;

end.

Der Server:

Delphi-Quellcode:
unit server;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, IdBaseComponent, IdComponent, IdTCPServer, StdCtrls;

type
  TForm1 = class(TForm)
    Server: TIdTCPServer;
    procedure ServerConnect(AThread: TIdPeerThread);
    procedure ServerExecute(AThread: TIdPeerThread);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

type
  TDynStringArray = array of string;


var
  Form1: TForm1;

implementation

{$R *.dfm}

function Explode(const Separator, S :String; Limit :Integer = 0): TDynStringArray;
  var
    SepLen: Integer;
    F, P: PChar;
begin
  SetLength(Result, 0);
  if (S = '') or (Limit < 0) then
    Exit;
  if Separator = 'then
    begin
      SetLength(Result, 1);
      Result[0] := S;
      Exit;
    end;
  SepLen := Length(Separator);

  P := PChar(S);
  while P^ <> #0 do
    begin
      F := P;
      P := AnsiStrPos(P, PChar(Separator));
      if (P = nil) or ((Limit > 0) and (Length(Result) = Limit - 1)) then
        P := StrEnd(F);
      SetLength(Result, Length(Result) + 1);
      SetString(Result[High(Result)], F, P - F);
      F := P;
      if P = Separator then
        SetLength(Result, Length(Result) + 1);
      while (P^ <> #0) and (P - F < SepLen) do
        Inc(P);
    end;
end;


procedure TForm1.ServerConnect(AThread: TIdPeerThread);
begin
  AThread.Connection.MaxLineLength := 1024*1024;
end;

procedure TForm1.ServerExecute(AThread: TIdPeerThread);
var
  Login: string;
  StrArr : TDynStringArray;
begin
  Login := AThread.Connection.ReadLn();

  if Length(Login) > 0 then
    begin
      StrArr := Explode('|', Login);
    end;

  if StrArr[0] = 'Loginthen
    begin
      if (StrArr[1] = 'Testuser') and (StrArr[2] = 'Testpass') then
        begin
          AThread.Connection.WriteLn('Connected');
        end
      else
        begin
          AThread.Connection.WriteLn('Passwort');
        end;
    end;

end;

end.
Er soll nur schauen ob die beiden eingaben übereinstimmen und ggf. das 3te Form entsprechend öffnen.

Da habe ich gleich noch eine weitere Frage: Gibts eine bessere möglichkeit aus mit Form.Visible zu arbeiten? Das scheint mir leider sehr uneffektiv zu sein. Leider komme ich mit Form2.Create(self) auch nicht wirklich weiter. Wenn jemand eine Idee hat ich bin für alles offen

http://img512.imageshack.us/img512/3553/13132123123.jpg
  Mit Zitat antworten Zitat
Benutzerbild von DataCool
DataCool

Registriert seit: 10. Feb 2003
Ort: Lingen
909 Beiträge
 
Delphi 10.3 Rio
 
#2

Re: Indy TCP Client-Server Problem

  Alt 14. Jul 2009, 08:36
Hi,

erstmal würde ich im Servercode die überprüfung der Userdaten ins OnConnect Event verschieben
und im OnExecute nur Deine "wirklichen" Kommandos verarbeiten.
Bei fehlerhaften Logindaten kann man auch ruhig mal die Connection dicht machen

Dein Hauptproblem ist aber Du anscheinend annimmst komplett mit Events im Client arbeiten zu können.
Es gibt aber kein OnData oder ähnliches.
Indy arbeitet mit "Blocking Sockets", die sauberste und eleganteste Lösung ist die komplette Kommunikation des Clients
in einen Thread auszulagern, damit erschlägst Du dann auch gleich ein paar andere Probleme(Einfrieren der Anwendung etc.).

Ich vermute das bei Dir das Event und ClientConnect Event gar nicht oder nicht dann eintritt, wenn Du es erwartest.

Du solltest so vorgehen:

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
Var sTmp : String;
begin
  Benutzername := Username.Text;
  Client.Connect(5000);
  if not Client.connected then
  begin
    ShowMessage('Konnte keine Verbindung herstellen');
    exit;
  end;
  // ShowMessage('Verbindung hergestellt');
  Client.Socket.Write('Login' + '|' + Form1.Username.Text + '|' + Form1.Passwort.Text);
  // spätestens ab hier sollte jetzt alles in einen Thread ausgelagert werden
  While Client.connected do
  begin
    sTmp := Client.Socket.Readln; // Read-Timeout vorher setzen oder über Parameter
    if sTmp <> 'then
    begin
      // mache irgentwas mit der Servernachricht
    end;
  end;
end;
So der grobe Ablauf, ohne Garantie(habs eben ohne IDE getippt).
Aber Auslesen der Serverdaten sollte definitiv innerhalb eines Threads ablaufen,

Greetz Data
Der Horizont vieler Menschen ist ein Kreis mit Radius Null, und das nennen sie ihren Standpunkt.
  Mit Zitat antworten Zitat
RedShakal
(Gast)

n/a Beiträge
 
#3

Re: Indy TCP Client-Server Problem

  Alt 14. Jul 2009, 16:36
Hab den Fehler gefunden ich habe .Write statt .WriteLn verwendet

Aber mal zurück zu dem Thema Threads, kannst du mir erklären wie man das benutzt? Gibts vielleicht sogar eine Bessere alternative (ausser Sockets)?
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 20:38 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz