Delphi / Indy. Длительная задержка в процедуре TIdStackWindows.Connect - PullRequest
0 голосов
/ 31 октября 2011

Мое приложение зависает при вызове процедуры 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, будет ли много миграции?

1 Ответ

4 голосов
/ 31 октября 2011

Блокирующие сокеты не имеют понятия тайм-аута соединения на уровне API, поэтому Indy's ConnectTimeout - это тайм-аут, реализованный вручную.Indy вызывает TIdStack.Connect() во внутреннем рабочем потоке, в то время как TIdTCPClient.Connect() выполняет цикл ожидания, который ожидает завершения этого потока.Если цикл обнаруживает, что период ConnectTimeout истек, он закрывает сокет, что должно привести к немедленному выходу заблокированного TIdStack.Connect(), но это не является гарантией.Существуют накладные расходы ОС при создании и завершении потока.Определенно, не нужно 30 секунд, чтобы среагировать на 1-секундный тайм-аут, но, с другой стороны, 1 секунда обычно слишком мала.Возможно, что поток даже не начнет работать в течение 1 секунды.Обычно вы должны установить ConnectTimeout на 5-10 секунд как минимум, чтобы дать ОС достаточно времени для ее работы.

...