connection - Indy10 ConnectTimeout 最小值
问题描述
我对ConnectTimeout
来自 Indy 10's 的产品有疑问TIdTCPClient
。
当设置ConnectTimeout
高于 125ms 时,Connect()
程序将阻塞当前线程 125ms。如果小于 125 毫秒,它将阻塞给定时间(例如,如果超时设置为 30 毫秒,它会阻塞 30 毫秒)。在这两种情况下,连接都是稳定的,我可以发送和接收数据。
为什么TIdTCPClient
会有这样的行为?
恕我直言,该Connect()
过程应在成功建立连接后直接退出,并且仅在无法打开连接时才阻止超时的全部持续时间。
这是我用于监控Connect()
程序持续时间的代码。
呼叫定时器TimerConnectTimer
设置为 250 毫秒。
我在 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;
解决方案
当设置
ConnectTimeout
高于 125ms 时,Connect()
程序将阻塞当前线程 125ms。如果小于 125 毫秒,它将阻塞给定时间(例如,如果超时设置为 30 毫秒,它会阻塞 30 毫秒)。在这两种情况下,连接都是稳定的,我可以发送和接收数据。为什么
TIdTCPClient
会有这样的行为?
如果不知道您使用的是哪个版本的 Indy 10,这很难回答,因为ConnectTimeout
多年来的实施已经发生了变化。但是,总的来说:
如果ConnectTimeout
设置为IdTimeoutDefault
or 0
,IdTimeoutInfinite
则改为使用。
如果Connect()
在主 UI 线程中调用,TIdAntiFreeze
正在使用,并且使用了无限超时,则使用硬编码的 2 分钟超时。
如果使用了任何超时,则Connect()
生成一个工作线程以将套接字连接到服务器,然后等待超时以使线程终止。如果在线程终止之前超时时间已过,Indy 将关闭套接字并终止线程。
假设您使用的是相当最新的 Indy 10 版本(至少 2016 年 12 月 14 日的 SVN 修订版 5382,或更高版本),并且没有使用TIdAntiFreeze
,那么仅在 Windows 上,当工作线程终止时,等待应该WaitForSingleObject()
立即退出,因为 Indy在线程上进行一次调用以获得完全超时并在退出后立即WFSO
退出。
如果您正在使用TIdAntiFreeze
,或者正在非 Windows 平台上使用 Indy,或者正在使用 SVN rev 5382 之前的 Indy 10 版本,则等待调用IndySleep()
(如果需要,TIdAntiFreeze.DoProcess()
)以固定间隔(125ms,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;
推荐阅读
- python - pytorch中expand的numpy等价物是什么?
- terraform - Terraform 使用 for_each 引用另一个模块的输出
- java - 使用 iText 将 SVG 图像转换为 PDF - 结果失真
- stm32 - STM32带编码器
- c# - 仅在 Windows 服务中:System.Runtime.InteropServices.COMException (0x800A03EC):来自 HRESULT 的异常:0x800A03EC
- python - 在 gitlab-ci 中 Pip 太慢了
- android-navigationview - 导航架构组件 - BottomNavigationView 锁定目标
- javascript - javascript - 检查项目中是否存在导入的模块,如果不使用某种回退
- html - HTML表单中文本输入类型的CSS不起作用
- c++ - C++ 中的双端队列