Delphi 2010 - у Wininet не хватает ручек

У меня есть приложение, которое интенсивно использует функции Wininet для получения данных из Интернета. Иногда я получаю очень странные сообщения об ошибках, связанные с дескриптором:

Internal error in ConnectToHost when trying to create a session 
ERROR_INTERNET_OUT_OF_HANDLES: No more handles could be generated at this time. Wininet error code = 12001;

Когда это произошло, я заметил, что в моем приложении создано более 5000 дескрипторов. Я запустил профиль ресурсов и обнаружил, что некоторые дескрипторы, созданные wininet, не освобождаются.

Итак, я создал небольшое приложение для воспроизведения проблемы. Код прост и ничего не делает, кроме как выделяет несколько дескрипторов wininet, а затем освобождает их. Это код:

procedure request(const AUrl : AnsiString);
var
  sMethod     : AnsiString;
  pSession    : HINTERNET;
  pConnection : HINTERNET;
  pRequest    : HINTERNET;
  port        : Integer;
  flags       : DWord;
begin
  pSession := InternetOpen(nil, INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
  if Assigned(pSession) then
  try
    Port := INTERNET_DEFAULT_HTTP_PORT;
    pConnection := InternetConnectA(pSession, PAnsiChar(AUrl), port, nil, nil, INTERNET_SERVICE_HTTP, 0, 0);
    if Assigned(pConnection) then
      try
        sMethod := 'GET';
        flags := INTERNET_SERVICE_HTTP;
        pRequest := HTTPOpenRequestA(pConnection, PAnsiChar(sMethod), PAnsiChar(AUrl), nil, nil, nil, flags, 0);
        try
          if Assigned(pRequest) then
            ShowMessage('ok');
        finally
          InternetCloseHandle(pRequest);
        end;
      finally
        InternetCloseHandle(pConnection);
      end;
  finally
    InternetCloseHandle(pSession);
  end;
end;

Запустив этот образец на моем профилировщике, я получаю те же проблемы, связанные с обработкой.

Я думаю, что InternetCloseHandle не освобождает дескриптор, как должно быть, потому что мой профиль ресурсов сообщает мне, что у меня есть 3 активных дескриптора, когда я закрываю приложение. Это дескрипторы, которые не освобождаются:

pRequest
pConnection
pSession

Кто-нибудь знает, как избавиться от этого?

ИЗМЕНИТЬ

Функция InternetCloseHandle работает нормально, возвращаемое значение true.

ИЗМЕНИТЬ

Я много искал в Интернете, но я не смог найти никого, кто жаловался бы на это. Но это происходит. Я хотел бы знать, воспроизвел ли кто-нибудь проблему или это только у меня.


person Rafael Colucci    schedule 03.08.2011    source источник
comment
AqTime: smartbear.com/products/development-tools/performance-profiling   -  person Rafael Colucci    schedule 04.08.2011
comment
Вам следует избегать открытия и закрытия дескрипторов, если вы выполняете тысячи запросов (ИМХО), попробуйте открыть дескриптор, сделать свое дело, а затем повторно использовать его, когда приложение закрывается, закройте дескриптор и вуаля. Однако, если ваш код выполняется в потоке, тогда это совсем другая история, переосмыслите процесс и придумайте самое быстрое решение, я не смог найти кого-то еще, кто жалуется на эту ошибку, я не слишком много искал. ...   -  person    schedule 04.08.2011
comment
@Dorin Я ничего не могу сделать. Wininet требует создания некоторых дескрипторов для каждого запроса, поэтому я должен их создать и освободить. Странно то, что я тоже не нашел, чтобы кто-то жаловался на это. Но профайлер не врет, что-то не так с InternetCloseHandle.   -  person Rafael Colucci    schedule 04.08.2011
comment
может быть, использовать TIdHTTP и посмотреть, будет ли у вас такой же результат? Я знаю, что он использует почти те же вызовы API, но должно быть что-то, что мы упускаем, можете ли вы воспроизвести проблему на нескольких ПК/ВМ?   -  person    schedule 04.08.2011
comment
Я только что провел тест (в Delphi XE), простой цикл, который делает 30 000 HTTP-запросов, используя ваш точный код, не имел никаких проблем, я предполагаю, что вы делаете что-то еще в коде с дескриптором, было бы полезно, если бы вы отправил бы весь код запроса, иначе сложно предположить, в чем может быть проблема.   -  person    schedule 04.08.2011
comment
У меня возникла проблема с кодом, который я разместил здесь. Ничего не изменилось, только этот код. Я предполагаю, что проблема связана с AQTime. Сегодня попробую другую программу. И, кстати, у Indy нет проблем, и он отлично работает.   -  person Rafael Colucci    schedule 04.08.2011


Ответы (2)


Оказалось, что это проблема AQtime. Скачал другой профилировщик и еще заглянул в Диспетчер задач и там вроде ручки освобождаются. Но я все еще иногда получаю ошибку no more handles, и я понятия не имею, почему. Но я открою другой вопрос, так как этот вопрос был просто для того, чтобы понять, почему эти ручки не освобождаются.

Спасибо за всю помощь, которую я получил.

person Rafael Colucci    schedule 05.08.2011
comment
Привет Рафаэль! Спасибо за размещение этого вопроса - команда разработчиков SmartBear смогла найти причину проблемы и устранить ее. Если вы хотите исправить проблему, обратитесь в службу технической поддержки SmartBear ( smartbear.com/support/message/?prod=AQtime ) и обратитесь к этой теме. - person Alex; 20.09.2011
comment
Без проблем! Рад, что смог помочь. Спасибо за такую ​​хорошую группу поддержки. - person Rafael Colucci; 20.09.2011

Протокол Http имеет некоторые ограничения, и Wininet их использует. Проверьте на лимит WinInet соединений на сервер:

WinInet ограничивает количество подключений к одному серверу HTTP 1.0 четырьмя одновременными подключениями. Подключения к одному серверу HTTP 1.1 ограничены двумя одновременными подключениями. Спецификация HTTP 1.1 (RFC2616) предписывает ограничение в два соединения. Ограничение на четыре соединения для HTTP 1.0 является самоустанавливающимся ограничением, которое совпадает со стандартом, используемым рядом популярных веб-браузеров.

Возможно, вам следует подождать, пока соединения не будут закрыты, прежде чем пытаться установить новое соединение.

person Daniel Luyo    schedule 03.08.2011
comment
Извините, но это не то, что я спросил. Я подключаюсь к разным серверам. Кроме того, я устанавливаю INTERNET_OPTION_MAX_CONNS_PER_SERVER INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER, чтобы убедиться. Мои соединения не в потоке. Мой код делает 1 соединение за раз. Но все равно спасибо. - person Rafael Colucci; 04.08.2011
comment
хорошо, вы пытались проверить возвращаемые значения в InternetCloseHandle? - person Daniel Luyo; 04.08.2011
comment
Нет, я не. Это должно было сработать, но я посмотрю на это. - person Rafael Colucci; 04.08.2011
comment
InternetCloseHandle работает нормально. Возвращаемое значение истинно. - person Rafael Colucci; 04.08.2011