AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Netzwerke Delphi TCP Client/Server: stabile Verbindung???
Thema durchsuchen
Ansicht
Themen-Optionen

TCP Client/Server: stabile Verbindung???

Ein Thema von romber · begonnen am 17. Mai 2007 · letzter Beitrag vom 20. Jun 2007
Antwort Antwort
Seite 1 von 2  1 2      
romber

Registriert seit: 15. Apr 2004
Ort: Köln
1.166 Beiträge
 
Delphi 10 Seattle Professional
 
#1

TCP Client/Server: stabile Verbindung???

  Alt 17. Mai 2007, 11:50
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:
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.
Client:

Delphi-Quellcode:
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.
Sicherlich mache ich etwas falsch. Wer kann mir helfen?
Angehängte Dateien
Dateityp: zip client-server_162.zip (20,2 KB, 9x aufgerufen)
  Mit Zitat antworten Zitat
romber

Registriert seit: 15. Apr 2004
Ort: Köln
1.166 Beiträge
 
Delphi 10 Seattle Professional
 
#2

Re: TCP Client/Server: stabile Verbindung???

  Alt 17. Mai 2007, 19:27
Kann mir keiner helfen?
  Mit Zitat antworten Zitat
Udontknow

Registriert seit: 17. Jun 2002
223 Beiträge
 
#3

Re: TCP Client/Server: stabile Verbindung???

  Alt 18. Mai 2007, 11:19
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
  Mit Zitat antworten Zitat
romber

Registriert seit: 15. Apr 2004
Ort: Köln
1.166 Beiträge
 
Delphi 10 Seattle Professional
 
#4

Re: TCP Client/Server: stabile Verbindung???

  Alt 18. Mai 2007, 17:06
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?
  Mit Zitat antworten Zitat
Benutzerbild von Luckie
Luckie

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#5

Re: TCP Client/Server: stabile Verbindung???

  Alt 18. Mai 2007, 17:16
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.
Michael
Ein Teil meines Codes würde euch verunsichern.
  Mit Zitat antworten Zitat
romber

Registriert seit: 15. Apr 2004
Ort: Köln
1.166 Beiträge
 
Delphi 10 Seattle Professional
 
#6

Re: TCP Client/Server: stabile Verbindung???

  Alt 18. Mai 2007, 17:19
Auch wenn ich den Sleep(1) auf mehrere Sekunden erhöhe, ändert das nichts. Die Fehler tauchen immer wieder auf.
  Mit Zitat antworten Zitat
Udontknow

Registriert seit: 17. Jun 2002
223 Beiträge
 
#7

Re: TCP Client/Server: stabile Verbindung???

  Alt 18. Mai 2007, 17:40
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:
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;
Gleichzeitig kannst du das ReadInteger nutzen, um eben bestimmte Anforderungen entgegen zu nehmen (die TCP-Verbindung wird ja normalerweise für Kommunikation genutzt).

Bis dann,

Andreas
  Mit Zitat antworten Zitat
romber

Registriert seit: 15. Apr 2004
Ort: Köln
1.166 Beiträge
 
Delphi 10 Seattle Professional
 
#8

Re: TCP Client/Server: stabile Verbindung???

  Alt 18. Mai 2007, 18:55
@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?
  Mit Zitat antworten Zitat
romber

Registriert seit: 15. Apr 2004
Ort: Köln
1.166 Beiträge
 
Delphi 10 Seattle Professional
 
#9

Re: TCP Client/Server: stabile Verbindung???

  Alt 19. Mai 2007, 15:03
Ich habe die Code modernisiert, so wie Udontknow geposetet hat. Dir Probleme sind aber immer noch da.
  Mit Zitat antworten Zitat
Benutzerbild von DataCool
DataCool

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

Re: TCP Client/Server: stabile Verbindung???

  Alt 21. Mai 2007, 23:15
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
Der Horizont vieler Menschen ist ein Kreis mit Radius Null, und das nennen sie ihren Standpunkt.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


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 19:51 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