Link to home
Start Free TrialLog in
Avatar of carmas123
carmas123

asked on

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

Avatar of 2266180
2266180
Flag of United States of America image

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

Avatar of carmas123
carmas123

ASKER

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

ASKER CERTIFIED SOLUTION
Avatar of 2266180
2266180
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
My Indy version is 10.1.5
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.
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

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.
I'VE SOLVED TY SO MUCH
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

B grade? did yuo read the grading tips?
Avatar of modus_operandi
Regraded.
 
modus_operandi
EE Moderator