3 Stimmen

Indy TCPClient OnDisconnect Ereignis funktioniert nicht

type
  TForm8 = class(TForm)
    idtcpclnt1: TIdTCPClient;
    idtcpsrvr1: TIdTCPServer;
    procedure FormCreate(Sender: TObject);
    procedure idtcpsrvr1Execute(AContext: TIdContext);
    procedure idtcpclnt1Disconnected(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form8: TForm8;

implementation

{$R *.dfm}

procedure TForm8.FormCreate(Sender: TObject);
begin
  idtcpclnt1.Connect;
end;

procedure TForm8.idtcpsrvr1Execute(AContext: TIdContext);
begin
  AContext.Connection.Disconnect(true); //this gets called
end;

procedure TForm8.idtcpclnt1Disconnected(Sender: TObject);
begin
  ShowMessage('true'); //but this does not
end;

Der OnDC wird nie bearbeitet. Warum eigentlich?

12voto

Remy Lebeau Punkte 498719

Indy-Client-Komponenten sind nicht ereignisgesteuert (mit ein paar Ausnahmen, wie TIdTelnet ). Die Website TIdTCPClient.OnDisconnect Ereignis wird NICHT ausgelöst, wenn der Server die Verbindung auf seiner Seite trennt, wie Sie vermuten. Das ist so gewollt. TIdTCPClient erfährt erst dann von der Trennung der Verbindung, wenn es erneut versucht, auf den Socket zuzugreifen, und löst dann eine Ausnahme aus, z. B. EIdConnClosedGracefully . Die TIdTCPClient.OnDisconnect wird nur ausgelöst, wenn das Ereignis TIdTCPClient.Disconnect() Methode auf der Client-Seite aufgerufen wird, was Sie nicht tun.

Zur Erkennung von serverseitigen Verbindungsabbrüchen mit TIdTCPClient müssen Sie in regelmäßigen Abständen aus dem Socket lesen, z. B. in einem Timer oder einem separaten Thread.

1voto

Rafael Colucci Punkte 5886

Ok, mein Fehler. Ihr Code funktioniert nicht, aber das ist richtig. Lassen Sie mich erklären, warum:

El AContext.Connection.Disconnect(true) Methodenaufrufe DisconnectNotifyPeer die in TCPServer nicht implementiert ist. Warum? Weil es nicht sein sollte.

Wenn Sie die Verbindung zum Server trennen, macht indy den Socket ungültig und schließt ihn. Der Client merkt erst dann, dass der Server die Verbindung getrennt hat, wenn er versucht, eine Anfrage zu senden. Und Ihr Code tut das nicht. Dies ist ein Standardverhalten von indy.

Um dem Client mitzuteilen, dass die Verbindung zum Server unterbrochen wurde, sollten indy und alle anderen Suiten das implementieren, was wir als heartbeat . Heartbeat ist eine Technik, die von Zeit zu Zeit versucht, kleine Pakete an einen Socket zu senden, um festzustellen, ob er noch lebt. Die einzige Möglichkeit, eine Socket-Unterbrechung zu erkennen, ist der Versuch, etwas in diesen Socket zu schreiben. Google über heartbeat und Sie werden verstehen, was ich meine.

EDITAR

チェック este aus.

1voto

Alex T Punkte 160

Sie können die Kunde POLL für das Trennen der Verbindung durch Hinzufügen einer Timer-Routine zur Kunde - Dies ist der einfachste Weg.

procedure TForm1.Timer1Timer(Sender: TObject);
   begin                    
      idTCPClient1.Connected;  // Works in Indy for Delphi XE4
   // Be aware this is a property read with side effects
   // It shouldn't get optimized out, but if it does, 
   // then add the appropriate directives to prevent that.
   end;                    

Dadurch sollte sich der Code genauso verhalten wie der alte TClientSocket (und wie das TidTelnet). Er erzeugt ein hsDisconnected-Flag für das OnStatus-Ereignis, wenn der Server plötzlich verschwindet (d.h. sobald die feuernde Timer-Routine dies erkennt). Allerdings wird in diesem speziellen Fall des Serververlusts, der die Trennung der Verbindung verursacht, NICHT das OnDisconnect-Ereignis ausgelöst, sondern nur das OnStatus-Ereignis. Daher ist es wahrscheinlich besser, immer OnStatus zu verwenden, um alle Verbindungsabbrüche zu erfassen, unabhängig davon, ob sie vom Client oder vom Server verursacht wurden. Ich habe einen auf 100ms eingestellten Timer verwendet, aber ich denke, man kann ihn so häufig oder langsam machen, wie man will - es scheint keinen Schaden anzurichten.

HINWEIS: Bei DELPHI 7 (und möglicherweise anderen Versionen zwischen D7 und XE4) müssen Sie dies etwas anders machen:

procedure TForm1.Timer1Timer(Sender: TObject);
   begin                    
   // This no longer works this way in Indy for XE4, but works in Indy for D7 ... 
      idTCPClient1.CheckForGracefulDisconnect(FALSE);  
   end; 

Übrigens - wenn Sie Delphi 6 verwenden, vergessen Sie Indy, es war damals einfach viel zu fehlerhaft.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X