0

我的应用程序正在调用 procedure TIdStackWindows.Connect。当 TCP/IP 地址存在时没有问题,但如果不存在,我就会挂起。IP 地址是文字 - 不涉及 DNS 查找。我期待连接尝试在超时(TCPClient.ConnectTimeout)后失败,我设置了 1 秒,但应用程序在此调用中最多挂起 30 秒(来自我的应用程序的调用没有线程。我打算将 TCP 连接移动到一个线程,但长连接超时仍然是一个问题)。

如果我在应用程序无响应时在 Delphi IDE 中暂停执行,我的定位是:

ntdll.KiUserApcDispatcher:
7C90E450 8D7C2410         lea edi,[esp+$10]

然后我 F8 几次,直到我看到一个堆栈帧。我当时在:

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 的最新版本,会涉及很多迁移吗?

4

1 回答 1

4

阻塞套接字在 API 层没有连接超时的概念,所以 IndyConnectTimeout是手动实现的超时。IndyTIdStack.Connect()在内部工作线程中调用,同时TIdTCPClient.Connect()运行等待该线程终止的睡眠循环。如果循环检测到ConnectTimeout时间已经过去,它会关闭套接字,这应该会导致阻塞TIdStack.Connect()立即退出,但这不是保证。创建和终止线程也有操作系统开销。对 1 秒超时做出反应绝对不需要 30 秒,但另一方面,1 秒通常太小。线程甚至可能不会在 1 秒内开始运行。您通常应该将ConnectTimeout至少设置为 5-10 秒,以便为操作系统提供足够的时间来完成其工作。

于 2011-10-31T05:18:24.607 回答