[Last Call] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 3225
  • Last Modified:

TidTCPClient and ConnectionTimeOut don't Work correctly

Hi, when i try to connect to a server with a TidTCPClient and the server is not found, my app is locked, why?
function TfrmMain.ConnectToServer: Boolean;
var
  LServerResponding: string;
begin
  {Initialization}
  Result := False;
  try
    {Connect to Server}
    with tcpClient do begin
      ConnectTimeout := 1000;
      ReadTimeout := 1000;
      Connect(Server_Host, Server_PortTCPIP);  // THE PROGRAM LOCK HERE
 
      IOHandler.WriteLn('myRequest');
      LServerResponding := IOHandler.ReadLn(LF, TCPIP_TIMEOUT);
      if LServerResponding <> TCPIP_RESP_OK then
        raise Exception.Create('Communication error.')
      else
        Result := True;
    end;
  except
  end;
end;

Open in new window

0
carmas123
Asked:
carmas123
  • 5
  • 5
1 Solution
 
2266180Commented:
here is my test code using indy 10.2.3
needless to say, it works. can you run this exact same code and tell me if it locks forever or not in your case?

note that somegarbagedomain.com does not exist, which is your intended scenario.
unit Unit1;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, IdTcpClient;
 
type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    tcpClient:TIdTcpClient;
    function ConnectToServer: Boolean;
  public
    { Public declarations }
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.dfm}
 
function TForm1.ConnectToServer: Boolean;
var
  LServerResponding: string;
begin
  {Initialization}
  Result := False;
  try
    {Connect to Server}
    with tcpClient do
    begin
      ConnectTimeout := 1000;
      ReadTimeout := 1000;
      Connect('somegarbagedomain.com', 1054);  // THE PROGRAM LOCK HERE
 
      IOHandler.WriteLn('myRequest');
      LServerResponding := IOHandler.ReadLn(#10, 1000);
      if LServerResponding <> 'ok' then
        raise Exception.Create('Communication error.')
      else
        Result := True;
    end;
  except
  end;
end;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  tcpclient:=TIdTcpClient.create(self);
  showmessage('connected to server? '+booltostr(ConnectToServer, true));
end;
 
end.

Open in new window

0
 
carmas123Author Commented:
Oh yes this work fine, but if I start this with a TTimer to start the connection with a delay time it won't work.

procedure TForm1.FormCreate(Sender: TObject);
begin
  tcpclient:=TIdTcpClient.create(self);
  myTimer:=TTimer.Create(Self);
  myTimer.Enabled := False;
  myTimer.Interval := 1000;
  myTimer.OnTimer := TimerToConnect;
  myTimer.Enabled := True;
end;
 
procedure TForm1.TimerToConnect(Sender: TObject);
begin
myTimer.Enabled:=False;
  showmessage('connected to server? '+booltostr(ConnectToServer, true));
end;

Open in new window

0
 
2266180Commented:
are you sure that is the exact code? because it works for me. which is normal, since if it works with no timer, it will work with timer as well.
what's your indy version?
unit Unit1;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, IdTcpClient, ExtCtrls;
 
type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    tcpClient:TIdTcpClient;
    myTimer:TTimer;
    function ConnectToServer: Boolean;
    procedure TimerToConnect(Sender: TObject);
  public
    { Public declarations }
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.dfm}
 
const lf=#10;
 
function TForm1.ConnectToServer: Boolean;
var
  LServerResponding: string;
begin
  {Initialization}
  Result := False;
  try
    {Connect to Server}
    with tcpClient do
    begin
      ConnectTimeout := 1000;
      ReadTimeout := 1000;
      Connect('somegarbagedomain.com', 1054);  // THE PROGRAM LOCK HERE
 
      IOHandler.WriteLn('myRequest');
      LServerResponding := IOHandler.ReadLn(LF, 1000);
      if LServerResponding <> 'ok' then
        raise Exception.Create('Communication error.')
      else
        Result := True;
    end;
  except
  end;
end;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  tcpclient:=TIdTcpClient.create(self);
  myTimer:=TTimer.Create(Self);
  myTimer.Enabled := False;
  myTimer.Interval := 1000;
  myTimer.OnTimer := TimerToConnect;
  myTimer.Enabled := True;
end;
 
procedure TForm1.TimerToConnect(Sender: TObject);
begin
  myTimer.Enabled:=False;
  showmessage('connected to server? '+booltostr(ConnectToServer, true));
end;
 
end.

Open in new window

0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
carmas123Author Commented:
My Indy version is 10.1.5
0
 
2266180Commented:
10.1.5 is full of bugs. and when I say full, I really mean full. there were a lot of issues reported with different components and different behaviours, many of them right here on EE.
I strongly suggest you upgrade to latest version. it's the only viable solution.
0
 
carmas123Author Commented:
Ok now i've installed the 10.2.3 version but the problem is not solved!!
I've, with debug, found where the program is locked.
The program lock when the command WaitFor in procedure DoConnectTimeout(ConnectTimeout); is executed.

I attach the source indy code where i've found the problem.
  procedure DoConnectTimeout(ATimeout: Integer);
  var
    LSleepTime: Integer;
    LInfinite: Boolean;
  begin
    if ATimeout = IdTimeoutDefault then begin
      ATimeout := IdTimeoutInfinite;
    end;
    LInfinite := ATimeout = IdTimeoutInfinite;
    with TIdConnectThread.Create(True) do try
      FBinding := Binding;
      Resume;
      // IndySleep
      if TIdAntiFreezeBase.ShouldUse then begin
        LSleepTime := IndyMin(GAntiFreeze.IdleTimeOut, 125);
      end else begin
        LSleepTime := 125;
      end;
 
      if LInfinite then begin
        ATimeout := LSleepTime + 1;
      end;
 
      while ATimeout > LSleepTime do begin
        IndySleep(LSleepTime);
 
        if LInfinite then begin
          ATimeout := LSleepTime + 1;
        end else begin
          ATimeout := ATimeout - LSleepTime;
        end;
 
        TIdAntiFreezeBase.DoProcess;
        if Terminated then begin
          ATimeout := 0;
          Break;
        end;
      end;
      IndySleep(ATimeout);
      //
      if Terminated then begin
        if FExceptionMessage <> '' then begin
          if FLastSocketError <> 0 then begin
            raise EIdSocketError.CreateError(FLastSocketError, FExceptionMessage);
          end;
          EIdConnectException.Toss(FExceptionMessage);
        end;
      end else begin
        Terminate;
        Close;
        WaitFor;   // THE PROGRAM LOCK HERE!!!
        EIdConnectTimeout.Toss(RSConnectTimeout);
      end;
    finally Free; end;
  end;

Open in new window

0
 
carmas123Author Commented:
I've been tested that when i try to set ConnectionTimeout to value < 9 (milliseconds) all work fine, if i try to set
the timeout to a >= 10 value, it's wont work.
0
 
carmas123Author Commented:
I'VE SOLVED TY SO MUCH
0
 
2266180Commented:
I donwloaded latest 10.2.3 version. tested and it still works. so, I am assuming you are still using the old version.

is the version showmessage displaying 10.2.3 ?
procedure TForm1.FormCreate(Sender: TObject);
begin
  tcpclient:=TIdTcpClient.create(self);
  showmessage(tcpclient.Version);// add this line
  myTimer:=TTimer.Create(Self);

Open in new window

0
 
2266180Commented:
B grade? did yuo read the grading tips?
0
 
modus_operandiCommented:
Regraded.
 
modus_operandi
EE Moderator
0

Featured Post

Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

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