![]() |
Indy TCP Client-Server Problem
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 :stupid:
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] = 'Connected' then 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] = 'Passwort' then begin showmessage('Benutzername und/oder Passwort falsch!'); Client.Disconnect; end; end; end; end. Der Server:
Delphi-Quellcode:
Er soll nur schauen ob die beiden eingaben übereinstimmen und ggf. das 3te Form entsprechend öffnen.
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] = 'Login' then 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. 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 ![]() |
Re: Indy TCP Client-Server Problem
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:
So der grobe Ablauf, ohne Garantie(habs eben ohne IDE getippt).
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; Aber Auslesen der Serverdaten sollte definitiv innerhalb eines Threads ablaufen, Greetz Data |
Re: Indy TCP Client-Server Problem
Hab den Fehler gefunden ich habe .Write statt .WriteLn verwendet :mrgreen:
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)? |
Alle Zeitangaben in WEZ +1. Es ist jetzt 16:06 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