Delphi/Indy. Long delay in procedure TIdStackWindows.Connect
我的应用程序挂在对过程TIdStackWindows.Connect的调用中。当TCP / IP地址存在时,就没有问题,但是如果没有,我就会死机。 IP地址是字面意义-不涉及DNS查找。我期望连接尝试在超时(TCPClient.ConnectTimeout)后失败,设置为1秒,但是此调用在该调用上挂起了30秒(我的应用程序的调用未线程化。我打算移动TCP连接到线程,但是长连接超时仍然是一个问题)。
如果我在应用程序无响应时暂停在Delphi IDE中执行,我的位置是:
1 2
| ntdll.KiUserApcDispatcher:
7C90E450 8D7C2410 lea edi,[esp+$10] |
然后我几次F8,直到看到堆栈框架。我当时在:
1 2 3 4 5 6 7 8 9 10 11 12
| IdStack.TIdStack.RaiseSocketError(10038)
IdStack.TIdStack.RaiseLastSocketError
IdStack.TIdStack.CheckForSocketError(-1)
IdStackWindows.TIdStackWindows.Connect(912,'10.8.2.170',5001,Id_IPv4)
IdSocketHandle.TIdSocketHandle.Connect
IdIOHandlerStack.TIdConnectThread.Execute
:00451fc1 HookedTThreadExecute + $2D
Classes.ThreadProc($254B910)
System.ThreadWrapper($5456CB0)
:00451ea3 CallThreadProcSafe + $F
:00451f10 ThreadExceptFrame + $3C
:7c80b729 ; C:\\WINDOWS\\system32\\kernel32.dll |
经过一番摸索后,我注意到该主题获得了一些访问量。常见的答案似乎是"将其放入线程"。我打算这样做,但是长时间超时仍然会带来问题。为什么连接超时不起作用?我正在使用Indy 10.5.5和Delphi 2006-如果我升级到最新版本的Indy,会涉及很多迁移吗?
阻塞套接字在API层没有连接超时的概念,因此Indy的ConnectTimeout是手动实现的超时。 Indy在内部工作线程中调用TIdStack.Connect(),而TIdTCPClient.Connect()运行一个睡眠循环,等待该线程终止。 如果循环检测到ConnectTimeout周期已过,则会关闭套接字,这可能会导致阻塞的TIdStack.Connect()立即退出,但这不能保证。 创建和终止线程也有OS开销。 绝对不应该花30秒来响应1秒钟的超时,但是另一方面,1秒钟通常太小。 该线程甚至有可能在一秒钟之内开始运行。 通常,您应该至少将ConnectTimeout设置为5-10秒,以使OS有足够的时间来完成其工作。
-
谢谢,雷米。 我对此表示怀疑,因为我已经看到有关此问题的其他评论,其中提到30秒(延迟也位于30秒的10mS之内-因此某个地方的源代码中可能有30000 mS的硬编码延迟)。 明天我会尝试更长的延迟,但我并不希望。
-
Indys代码中没有30秒的硬编码延迟(但是,如果ConnectTimeout为0,则存在2分钟的硬编码超时)。 请参见IdIOHandlerStack.pas中TIdIOHandlerStack.ConnectClient()的实现。 在connect()繁忙时运行的睡眠循环确实在每个循环迭代中使用125 ms(最大)睡眠,但是API部分会花费大量的延迟,从而最多增加30秒。 请注意,如果您在主线程内调用TIdTCPClient.Connect(),并且使用的是TIdAntiFreeze组件,则Indy之外的VCL主消息队列可能会导致其他延迟。
-
延迟30000 mS时,我想到的是Windows,而不是Indy! :)