![]() |
TCP Client/Server: stabile Verbindung???
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo!
Das Programm führt verschiedene Anylisen durch und schickt die Ergebnisse sofort an alle verbundene Clients. Es ist sehr wichtig, dass die Verbindung sofort wieder aufgebaut wird, falls diese aus irgendeinem Grund unterbrochen wurde. Die Code, die ich mir dafür gebastelt habe, funktioniert, es ist aber irgendwo Hacken drin. Irgendwann springt die CPU-Auslastung auf 100%, die Anzeige der verbundenen Clienten spinnt und als Folge wird das Client-Programm stumm terminiert. Zack - einfach weg, als on man das Programm geschlossen hat. Server:
Delphi-Quellcode:
Client:
unit Unit1;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, IdBaseComponent, IdComponent, IdTCPServer, StdCtrls; type TForm1 = class(TForm) IdTCPServer1: TIdTCPServer; Timer1: TTimer; Label1: TLabel; procedure IdTCPServer1Connect(AThread: TIdPeerThread); procedure FormCreate(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure IdTCPServer1Disconnect(AThread: TIdPeerThread); procedure IdTCPServer1Execute(AThread: TIdPeerThread); procedure Timer1Timer(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } end; type TClientClass = class private PeerThread: TIdPeerThread; end; var Form1: TForm1; fClientList: TList; //Liste für verbundene Client ListData: TStringList; //In dieser Liste landen die Daten, die dann an die Clienten verschickt werden implementation {$R *.dfm} procedure TForm1.IdTCPServer1Connect(AThread: TIdPeerThread); begin AThread.Data := TClientClass.Create(); fClientList.Add(AThread.Data); TClientClass(AThread.Data).PeerThread := AThread; end; procedure TForm1.FormCreate(Sender: TObject); begin fClientList := TList.Create; ListData := TStringList.Create; end; procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin fClientList.Free; ListData.Free; end; procedure TForm1.IdTCPServer1Disconnect(AThread: TIdPeerThread); begin fClientList.Delete(fClientList.IndexOf(AThread.Data)); end; procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread); var i: integer; LastIndex: integer; NoData: integer; lCount: integer; begin LastIndex := ListData.Count; while AThread.Connection.Connected do begin Sleep(1); if ListData.Count > LastIndex then begin NoData := 0; lCount := ListData.Count; for i := lCount - 1 - LastIndex downto 0 do AThread.Connection.WriteLn(ListData.Strings[i] + '|~|'); LastIndex := lCount; end else // Wenn die Verbidunung zu einem Client unerwartet begin // abgebrochen wird, merkt das der Server erst, wenn NoData := NoData + 1; // er versucht, irgendwas zu schicken. Dafür ist dieses if NoData >= 100 then // Teil da. begin AThread.Connection.WriteLn(); NoData := 0; end; end; end; end; procedure TForm1.Timer1Timer(Sender: TObject); begin Label1.Caption := IntToStr(fClientList.Count) + ' aktive Verbindungen'; end; end.
Delphi-Quellcode:
Sicherlich mache ich etwas falsch. Wer kann mir helfen? :roll:
unit Unit1;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, StdCtrls; type TForm1 = class(TForm) cbConnect: TCheckBox; procedure cbConnectClick(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } end; type TCheckConnection = class(TThread) protected procedure Execute; override; end; type TClientTCP = class(TThread) constructor Create (CreateSuspended: Boolean); destructor Destroy; override; private TempData: string; CheckConnection: TCheckConnection; protected procedure Execute; override; procedure TCPClientStatus(ASender: TObject; const AStatus: TIdStatus; const AStatusText: String); public TCPClient: TIdTCPClient; end; var Form1: TForm1; TCPConnection: TClientTCP; CheckConnectionCounter: integer; implementation {$R *.dfm} procedure TCheckConnection.Execute; begin FreeOnTerminate := true; while not Terminated do begin CheckConnectionCounter := CheckConnectionCounter + 1; if CheckConnectionCounter = 5 then begin TCPConnection.TCPClient.Disconnect; Terminate; end; Sleep(1000); end; end; constructor TClientTCP.Create(CreateSuspended: Boolean); begin inherited Create(CreateSuspended); FreeOnTerminate := true; end; destructor TClientTCP.Destroy; begin Sleep(1); TCPConnection := nil; if Form1.cbConnect.Checked then begin if not Assigned(TCPConnection) then TCPConnection := TClientTCP.Create(false); end; if Assigned(CheckConnection) then CheckConnection.Terminate; end; procedure TClientTCP.Execute; var x, Data: string; begin CheckConnectionCounter := 0; TCPClient := TIdTCPClient.Create(nil); TCPClient.OnStatus := TCPClientStatus; TCPClient.Host := 'localhost'; TCPClient.Port := 55595; try TCPClient.Connect; CheckConnection := TCheckConnection.Create(false); while not Terminated and TCPClient.Connected do begin CheckConnectionCounter := 0; x := TCPClient.ReadLn; Data := TempData + x; TempData := ''; while pos('|~|', Data) > 0 do begin //TAnalyseData.Create(false, Copy(Data, 1, Pos('|~|', Data) - 1)); Delete(Data, 1, Pos('|~|', Data) + 3); end; if Length(Data) > 0 then TempData := Data; end; except end; if TCPClient.Connected then TCPClient.Disconnect; TCPClient.Free; end; procedure TClientTCP.TCPClientStatus(ASender: TObject; const AStatus: TIdStatus; const AStatusText: String); begin if AStatus = hsConnected then begin Form1.cbConnect.Caption := 'verbunden'; exit; end; if (AStatus = hsDisconnected) or (AStatus = hsDisconnecting) then begin if Form1.cbConnect.Checked then Form1.cbConnect.Caption := 'Verbindung wird hergestellt...' else Form1.cbConnect.Caption := 'nicht verbunden'; exit; end; end; procedure TForm1.cbConnectClick(Sender: TObject); begin if cbConnect.Checked = true then begin cbConnect.Caption := 'Verbindung wird hergestellt...'; if not Assigned(TCPConnection) then TCPConnection := TClientTCP.Create(false); end else begin if Assigned(TCPConnection) then begin TCPConnection.Terminate; cbConnect.Caption := 'nicht verbunden'; end; end; end; end. |
Re: TCP Client/Server: stabile Verbindung???
Kann mir keiner helfen? :(
|
Re: TCP Client/Server: stabile Verbindung???
Hallo!
Ich habe mal grob drübergeblickt, und die ServerExecute-Routine sieht doch sehr merkwürdig aus: Du sendest einfach in einer Schleife wild drauf los. Was soll das? Wäre es nicht besser, die Daten nur einmal bzw. bei Anfrage vom Client zu senden? Wieso muss man überhaupt sofort erfahren, daß der Client unerwartet verschwunden ist? Cu, Udontknow |
Re: TCP Client/Server: stabile Verbindung???
Wie schwer das auch zu vostellen ist, es gibt Martktbereiche, wo jede Sekunde zählt. Für so ein Marktbereich ist mein Programm gedacht.
Was mache ich falsch, dass oben beschriebene Fehler passieren? |
Re: TCP Client/Server: stabile Verbindung???
1. Windows ist kein EChtzeit Betriebssystem und somit nicht für zeitkritische Anwnedungen geeignet und
2. kann man sich nicht auf die Geschwindigkeit einer Netzwerkverbindung verlassen. Du solltest also dein Konzept noch mal überdenken. |
Re: TCP Client/Server: stabile Verbindung???
Auch wenn ich den Sleep(1) auf mehrere Sekunden erhöhe, ändert das nichts. Die Fehler tauchen immer wieder auf.
|
Re: TCP Client/Server: stabile Verbindung???
Du solltest das trotzdem umbauen. Ein Server, der dauernd pollt, ist nicht so toll.
Vorschlag: Verwende doch ein ReadInteger, den der Server standardmäßig aufruft. Sowohl bei Verbindungsabbrüchen als auch bei normalen Beendigungen des Clients wirst du eine Indy-Exception erhalten. Hier der Code:
Delphi-Quellcode:
Gleichzeitig kannst du das ReadInteger nutzen, um eben bestimmte Anforderungen entgegen zu nehmen (die TCP-Verbindung wird ja normalerweise für Kommunikation genutzt).
procedure TForm67.TCPServerExecute(AContext: TIdContext);
var Stream:TMemoryStream; var Command:Integer; begin try Command:=AContext.Connection.IOHandler.ReadInteger(); except HandleClientLost; //<- Routine, die bei IdExceptions dann getriggert wird raise; end; //Hier Code für die Interpretierung des Commands hinterlegen if Command=0 then ... end; Bis dann, Andreas |
Re: TCP Client/Server: stabile Verbindung???
@Udontknow
Danke! Sieht gut aus, werde ich gleich probieren. Aber kann jemand in meinem Server-Code ein dummes Fehler erkennen (außer dem, was Udontknow schon bemerkt hat), das zu einem plötzlichen Anstieg der CPU-Auslastung auf 100% führen könnte? Oder soll ich die Ursache in dem übrigen Code suchen? Und wo liegt das Problem an dem Client? Das Client-Programm verschwindet von selbst. Wo liegt dort das Fehler? |
Re: TCP Client/Server: stabile Verbindung???
Ich habe die Code modernisiert, so wie Udontknow geposetet hat. Dir Probleme sind aber immer noch da.
|
Re: TCP Client/Server: stabile Verbindung???
Hi,
bin leider nicht dazu gekommen, in die Tiefe des Code zu schauen. Aber ich kann Dir mit Sicherheit sagen, das Du mit Indy9 oder auch mit Indy10 das ganze ohne Probleme realisieren kannst. Ich mache ähnliches mit 50-100 Clients an einem Server ohne Probleme, wobei ich die Disconnects der Clients nur jede Minute überprüfe. Aber bei normalen Disconnects melden sich die Clients auch regulär ab. Was ich Dir damit sagen will, ist das gleihe was meine Vorgänger auch schon gesagt haben : Bei einer Server/Client Anwendung muss die Struktur und das Protokoll genau bedacht/entworfen seien. Wie schnell musst Du wirklich wissen, ob ein Client nicht mehr verbunden ist ? Wäre es nicht ausreichend, wenn der Client merkt wenn die Verbindung zum Server unterbrochen ist und sich umgehend neu verbindet ? In diesem Fall müßtest Du nur die Daten, die "ausgeliefert" werden sollen, zwischen speichern, und dazu speichern welcher Client welche Daten bekommen hat. Erzähl mal näheres über die Art der Daten die Du austauschen willst, die Rahmenbediengungen unter denen das ganze ablaufen soll und den "Sinn und Zweck" des ganzen ;-) Gruß DataCool |
Alle Zeitangaben in WEZ +1. Es ist jetzt 12:26 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 by Thomas Breitkreuz