我有一个关于印地10的TIdTCPClient的ConnectTimeout的问题。
当将ConnectTimeout设置为大于125ms时,Connect()过程将阻塞当前线程125ms。如果它小于125ms,它将在给定的时间内阻塞(例如,如果超时设置为30ms,它将阻塞30ms)。在这两种情况下,连接都是稳定的,我可以发送和接收数据。
为什么TIdTCPClient会有这样的行为?
IMHO Connect()过程应该在成功建立连接后立即退出,并且只有在没有连接可以打开的情况下才阻止超时的整个持续时间。
下面是我用来监控Connect()过程持续时间的代码。
调用TimerConnectTimer的定时器设置为250ms。
我使用的是Windows7专业版下的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;发布于 2018-11-13 04:39:34
当将
ConnectTimeout设置为大于125ms时,Connect()过程将阻塞当前线程125ms。如果它小于125ms,它将在给定的时间内阻塞(例如,如果超时设置为30ms,它将阻塞30ms)。在这两种情况下,连接都是稳定的,我可以发送和接收数据。
为什么TIdTCPClient会有这样的行为?
如果不知道您使用的是Indy10的确切版本,就很难回答这个问题,因为这些年来ConnectTimeout的实现已经发生了变化。但是,总的来说:
如果ConnectTimeout设置为IdTimeoutDefault或0,则使用IdTimeoutInfinite。
如果在主UI线程中调用Connect(),则使用TIdAntiFreeze,并且使用无限超时,则使用硬编码的2分钟超时。
如果使用了超时,Connect()会产生一个工作线程来将套接字连接到服务器,然后一直等待到超时,直到线程终止。如果在线程终止之前超时,Indy将关闭套接字并终止线程。
假设您使用的是Indy10的最新版本(至少是2016年12月14日的SVN5382版或更高版本),并且没有使用TIdAntiFreeze,那么仅在Windows上,等待应在工作线程终止时立即退出,因为Indy在整个超时期间对线程上的WaitForSingleObject()进行一次调用,并在WFSO退出时立即退出。
如果您使用的是TIdAntiFreeze,或者在非Windows平台上使用Indy,或者使用的是SVN rev 5382之前的Indy10版本,等待会以固定的时间间隔(125ms或TIdAntiFreeze.IdleTimeOut,取较小者)在循环中调用IndySleep() (如果需要,还会调用TIdAntiFreeze.DoProcess()),直到超时或线程终止。在这种情况下,在Connect()退出之前可能会有一个轻微的延迟,因为每个休眠周期必须在Connect()可以检查线程是否已经终止之前完成,并且在整个连接超时内对每个休眠间隔执行此操作。
IMHO
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;https://stackoverflow.com/questions/53261747
复制相似问题