• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1461
  • Last Modified:

Can a TIdTCPClient monitor a connection

Hi Experts,
I use a Indy version 9 TIdTCPClient to connect to units in the field.
The Unit in the field kicks me out after five minutes of inactivity.
Is there a way for the TIdTCPClient to know when a connection is droped so that a message box can be displayed to the user.
Example of code appreciated.
0
QurbanDurrani
Asked:
QurbanDurrani
  • 3
  • 3
1 Solution
 
HypoCommented:
Hi,
I think you must call the function TIdTCPClient.CheckForGracefulDisconnect to update the status of the Connected property of the TIdTCPClient-object. By putting that test in a timer, you can trigger that message-box to appear when the units drop you connection.

My example belows shows that function placed in a loop. Create a new form to where you add one TIdTCPClient, one TIdTCPServer, one TMemo and one TButton... then Add the sourcecode below and connect the events to the objects.

regards
Hypo
unit Unit1;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, IdCustomTCPServer, IdTCPServer, IdBaseComponent, IdComponent,
  IdTCPConnection, IdTCPClient, IdContext, StdCtrls;
 
type
  TForm1 = class(TForm)
    IdTCPClient1: TIdTCPClient;
    IdTCPServer1: TIdTCPServer;
    Memo1: TMemo;
    Button1: TButton;
    procedure IdTCPServer1Execute(AContext: TIdContext);
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.dfm}
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  IdTCPClient1.Host := '127.0.0.1';
  IdTCPClient1.Port := 5050;
  IdTCPClient1.ReadTimeout := 5000;
  IdTCPServer1.DefaultPort := 5050;
  IdTCPServer1.Active := True;
end;
 
procedure TForm1.Button1Click(Sender: TObject);
var sText : String;
begin
  IdTCPClient1.Connect;
  While IdTCPClient1.Connected do begin
    sText := IdTCPClient1.IOHandler.ReadLn;
    if IdTCPClient1.IOHandler.ReadLnTimedout
      then IdTCPClient1.CheckForGracefulDisconnect(False)
      else Memo1.Lines.Add(sText);
  end;
  Memo1.Lines.Add('Finished');
end;
 
procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
begin
  AContext.Connection.IOHandler.WriteLn('Sleeping for 3 sek and then disconnects...');
  AContext.Connection.IOHandler.WriteBufferFlush;
  Sleep(3000);
  AContext.Connection.IOHandler.WriteLn('Server is now disconnecting...');
  AContext.Connection.IOHandler.WriteBufferFlush;
  AContext.Connection.Disconnect;
end;
 
end.

Open in new window

0
 
QurbanDurraniAuthor Commented:
Hypo,
Thanks a bunch for your response. I have been trying to understand it.
1) What exactly does the CheckForGracefulDisconnect(False) do? I read the Delphi help but could not understand it completely.
2) Do I have to do a "ReadLn" and in case it times out I proceed to CheckForGracefulDisconnect(False).
3) If I understand it correctly, I would put code in the "Ontimer" event of the timer to call CheckForGracefulDisconnect(False), Which would update the "connected" property of the TCPClient. Next It would check the "connected" property and if it is false, a message box would pop up displaying a message about disconnection. Is that accurate?
Thanks for your help again.
0
 
HypoCommented:
1:
I haven't analyzed the code behind the CheckForGracefulDisconnect function, but my experience from using it tells me that it validates that the internal socket handle is still valid, which in simple terms means that it can validate that a connection is still open, and has not been closed without you being notified about it. I think it's quite normal that you do this check to see that the connection is still valid, when you have a read or write that times out.

2:
You don't have to use the readln, you can call CheckForGracefulDisconnect from anywhere, and it will update the status regardless of if you had a previous timeout or not. I just added it to make some more sense in the example.

3:
Yes, that is correct. Also, If you call CheckForGracefulDisconnect(True) (which is the default parameter) then it will trigger an exception if it has become disconnected. If not captured, this exception will show a dialog; so that's a quick way of testing this notify. But I think you should do the flow you described above anyway, because most of the times, I don't think it's good practice to use exceptions to trigger an effect that you can acheive by just doing some extra lines of code.

regards
Hypo
0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
QurbanDurraniAuthor Commented:
Thanks Hypo.
Good explaination. I will try this when I go in to work tomorrow morning.
1) When calling CheckForGracefulDisconnect, what is the True/False parameter for?
2) If the timer calls the CheckForGracefulDisconnect while my application is either sending or receiving data, will it cause any problems?
3) So If the timer is sechelued every five seconds, will I not just keep getting the pop up message every five seconds while the connections is closed. I guess the timer is disabled at design time. The timer is enabled once a connection is established and it is disabled when the connection is closed by clicking the disconnect button or when the CheckForGracefulDisconnect  determines that the connection has been lost. Does this seem like a reasonable approach?
0
 
HypoCommented:
Hi,
1:
The True/False parameter determines if CheckForGracefulDisconnect should raise an exception or not when it discovers that the connection was closed. I think this was always set to true in the earlier versions of Indy, but I guess it generated too many questions for the indy team, when people who were unfamiliar with exception handling got these errors, so they made it optional instead.

2:
If you have a seperate thread that is doing the sending and receiving, then you have to synchronize the sending/reciving and the connection check with a CriticalSection-object, or It could cause problems. If you do your sending/receiving in the main thread of your application, then It will not be a problem. The reason for that is because a timer event runs from the main thread, and can therefore not be executed at the same time as the main thread does something else (like sending/receiveng data). Threads make parallell code, timers do not.

3:
If you have that test in a timer, then I think you should only display that dialoge the first time you discover that the socket is disconnected. If your socket _is_ connected, and CheckForGracefullDisconnect sets the connected state to false, then you display that dialoge. If the socket is already in a disconnected state when you enter the timer, then you do nothing. The idea you have about enabling and disabling the timer sounds reasonable, and yes, the timer is disabled at design time. :)

regards
Hypo
0
 
QurbanDurraniAuthor Commented:
Thanks a Bunch Hypo for taking the time to provide detailed explaination.
Regards
Qurban
0

Featured Post

Prep for the ITIL® Foundation Certification Exam

December’s Course of the Month is now available! Enroll to learn ITIL® Foundation best practices for delivering IT services effectively and efficiently.

  • 3
  • 3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now