我对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;
答案 0 :(得分:0)
将
ConnectTimeout
设置为高于125ms时,Connect()
过程将阻塞当前线程125ms。如果小于125毫秒,则会在给定的时间内阻塞(例如,如果超时设置为30毫秒,则会阻塞30毫秒)。在这两种情况下,连接都是稳定的,我可以发送和接收数据。
TIdTCPClient
为什么会这样?
由于ConnectTimeout
的实现多年来已发生变化,因此如果不确切知道使用的是哪个Indy 10版本,很难回答。但是,通常:
如果将ConnectTimeout
设置为IdTimeoutDefault
或0
,则使用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;