Indy10 ConnectTimeout最小值

时间:2018-11-12 12:00:33

标签: connection timeout client freepascal indy10

我对Indy 10的ConnectTimeout中的TIdTCPClient有疑问。

ConnectTimeout设置为高于125ms时,Connect()过程将阻塞当前线程125ms。如果小于125毫秒,则会在给定的时间内阻塞(例如,如果超时设置为30毫秒,则会阻塞30毫秒)。在这两种情况下,连接都是稳定的,我可以发送和接收数据。

TIdTCPClient为什么会这样?

恕我直言,Connect()过程应在成功建立连接后立即退出,并且如果无法打开连接,则仅阻塞整个超时时间。

这是我的代码,用于监视Connect()过程的持续时间。
呼叫TimerConnectTimer的计时器设置为250ms。

我正在Windows 7 Professional下使用Lazarus v1.6.4和Indy 10。

procedure TForm1.FormCreate(Sender: TObject);
begin
  timer := TEpikTimer.create(self);
  timer.Clear;
end;

procedure TForm1.TimerConnectTimer(Sender: TObject);
begin
  timer.Start;
  client := TIdTCPClient.create();
  logTime(0);
  // Tested with values between 10ms and 1000ms
  client.ConnectTimeout := SpinEdit1.Value;
  try
    logTime(1);
    // choose ip and port for a running server
    client.connect('192.168.2.51', 9912);
    logTime(2);
  except

  end;

  logTime(3);

  try
    client.Disconnect();
    FreeAndNil(client);
  except

  end;

  logTime(4);
  timer.Clear;
end;

procedure TForm1.logTime(ch: integer);
begin
  StringGrid1.Cells[0, ch] := FormatFloat('0.00', timer.Elapsed*1000);
end;

1 个答案:

答案 0 :(得分:0)

  

ConnectTimeout设置为高于125ms时,Connect()过程将阻塞当前线程125ms。如果小于125毫秒,则会在给定的时间内阻塞(例如,如果超时设置为30毫秒,则会阻塞30毫秒)。在这两种情况下,连接都是稳定的,我可以发送和接收数据。

     

TIdTCPClient为什么会这样?

由于ConnectTimeout的实现多年来已发生变化,因此如果不确切知道使用的是哪个Indy 10版本,很难回答。但是,通常:

如果将ConnectTimeout设置为IdTimeoutDefault0,则使用IdTimeoutInfinite

如果在主UI线程中调用Connect(),则使用TIdAntiFreeze,并且使用了无限超时,而是使用了硬编码的2分钟超时。

如果使用了任何超时,Connect()会生成一个工作线程来将套接字连接到服务器,然后等待超时直到线程终止。如果在线程终止之前超时已到,Indy将关闭套接字并终止线程。

假设您使用的是Indy 10的最新版本(至少在2016年12月14日或之后的SVN版本5382或更高版本),并且未使用TIdAntiFreeze,则仅在Windows上,等待当工作线程终止时,应该立即退出,因为Indy在线程上对WaitForSingleObject()进行了一次完整超时的调用,并在WFSO退出后立即退出。

如果您正在使用TIdAntiFreeze,或者在非Windows平台上使用Indy,或者正在使用SVN rev 5382之前的Indy 10版本,则等待调用IndySleep()(并且如果需要的话) ,TIdAntiFreeze.DoProcess())以固定间隔(125毫秒或TIdAntiFreeze.IdleTimeOut,以较小者为准)循环循环,直到超过超时或线程终止为止。在这种情况下,Connect()退出之前可能会稍有延迟,因为每个睡眠周期必须在Connect()可以检查线程是否已终止之前完成,并且这样做在整个连接超时时间内的每个睡眠间隔。

  

恕我直言,Connect()过程应在成功建立连接后立即退出,并且如果无法打开连接,则仅阻塞整个超时时间。

至少在Windows上,这正是当前的功能。如果连接成功,则线程终止,Connect()立即退出(即使使用了TIdAntiFreeze)。当前的睡眠周期通过线程自身终止而结束。在非Windows平台上不是这种情况(目前可能会在将来的版本中解决)。

请注意,以上所有内容仅在使用超时时适用。如果不使用超时,则也不使用任何工作线程。 Connect()只需直接连接套接字,就可以尝试阻止调用线程直到完成,无论是否成功。

  

这是我的代码,用于监视Connect()过程的持续时间。

我建议改成这样:

procedure TForm1.TimerConnectTimer(Sender: TObject);
begin
  try
    timer.Start;
    try
      logTime(0);

      client := TIdTCPClient.create();
      try
        // choose ip and port for a running server
        client.Host := '192.168.2.51';
        client.Post := 9912;

        // Tested with values between 10ms and 1000ms
        client.ConnectTimeout := SpinEdit1.Value;

        logTime(1);
        client.Connect();
        logTime(2);
        client.Disconnect();
        logTime(3);

      finally
        FreeAndNil(client);
      end;

      logTime(4);
    finally
      timer.Clear;
    end;
  except
  end;
end;