InternetOpenUrl возвращается только после загрузки всего HTTP-ответа

Я пишу утилиту загрузки файлов с помощью WinINET и заметил (особенно при больших загрузках), что вызов WinINET InternetOpenUrl () возвращается только после весь ответ HTTP был загружен.

Я подтвердил это с помощью прокси-инструмента Charles, а также с помощью WireShark, и заметил, что загрузка завершается полностью, и только после этого WinINET уведомляет мой код.

Некоторый упрощенный (синхронный) код:

hInt = InternetOpen(USER_AGENT_NAME, INTERNET_OPEN_TYPE_PRECONFIG, 
                    NULL, NULL, 0);
DWORD dwRequestFlags = INTERNET_FLAG_NO_UI   // no UI please
            |INTERNET_FLAG_NO_AUTH           // don't authenticate
            |INTERNET_FLAG_PRAGMA_NOCACHE    // do not try the cache or proxy
            |INTERNET_FLAG_NO_CACHE_WRITE;   // don't add this to the IE cache

hUrl = InternetOpenUrl(hInt, szURL, NULL, 0, dwRequestFlags, NULL);
if (hUrl)
{
  // 

  InternetCloseHandle(hUrl);
}
InternetCloseHandle(hInt);

В документации предлагается , что он отправляет запрос и обрабатывает заголовки ответа (не завершая загрузку), а затем вы должны выполнить цикл InternetReadFile () до тех пор, пока он не вернет TRUE , а dwNumberOfBytesRead равно 0.

Из MSDN
Функция InternetOpenUrl : Функция InternetOpenUrl анализирует строку URL-адреса, устанавливает соединение с сервером и подготавливает к загрузке данных, идентифицированных URL-адресом. Затем приложение может использовать InternetReadFile [...] для получения данных URL.

Функция InternetReadFile : и обрабатывает заголовки ответа (не завершая загрузку), а затем вы должны выполнить цикл InternetReadFile () , пока он не вернет TRUE и dwNumberOfBytesRead равно 0.

Из MSDN
Функция InternetOpenUrl : Функция InternetOpenUrl анализирует строку URL, устанавливает соединение с сервером и подготавливает для загрузки данных, идентифицированных URL-адрес. Затем приложение может использовать InternetReadFile [...] для получения данных URL.

Функция InternetReadFile : и обрабатывает заголовки ответа (не завершая загрузку), а затем вы должны выполнить цикл InternetReadFile () , пока он не вернет TRUE и dwNumberOfBytesRead равно 0.

Из MSDN
Функция InternetOpenUrl : Функция InternetOpenUrl анализирует строку URL, устанавливает соединение с сервером и подготавливает к загрузке данных, идентифицированных URL-адрес. Затем приложение может использовать InternetReadFile [...] для получения данных URL.

Функция InternetReadFile :

Из MSDN
Функция InternetOpenUrl : Функция InternetOpenUrl анализирует строку URL-адреса, устанавливает соединение с сервером и подготавливает к загрузке данных, идентифицированных URL-адресом. Затем приложение может использовать InternetReadFile [...] для получения данных URL.

Функция InternetReadFile :

Из MSDN
Функция InternetOpenUrl : Функция InternetOpenUrl анализирует строку URL-адреса, устанавливает соединение с сервером и подготавливает к загрузке данных, идентифицированных URL-адресом. Затем приложение может использовать InternetReadFile [...] для получения данных URL.

Функция InternetReadFile : Чтобы гарантировать получение всех данных, приложение должно продолжать вызывать функцию InternetReadFile до тех пор, пока функция не вернет значение ИСТИНА и параметр lpdwNumberOfBytesRead не станет равным нулю.

Я пробовал это, используя асинхронный метод, и заметил то же самое. В частности, INTERNET_STATUS_RESPONSE_RECEIVED отправляется зарегистрированному методу обратного вызова только после завершения загрузки. Это означает, что мой клиент может начать доступ к данным только после завершения загрузки.

Аналогичным образом, я реализовал версию, которая также использует библиотеку WinHttp, и заметил точно такие же результаты.

Это делает вещи сложно, когда дело доходит до тайм-аутов. Если загрузка превышает время ожидания (по умолчанию 30 секунд), InternetOpenUrl () завершается ошибкой.

Итак, у меня два вопроса:

Если это ожидаемое поведение библиотек WinInet и WinHttp, почему в документации предлагается выполнить цикл через вызов InternetReadFile () , почему бы просто не прочитать весь буфер (в конце концов, WinINET уже имеет)?

Я понимаю, что предоставляю такую ​​возможность, поскольку вы не всегда хотите выделять блоки памяти по 150 Мбайт, но оправдание заключается в том, что вы не знаете, сколько данных доступно ... но WinINET уже завершил загрузку.

И почему он выглядит так, как упакованный метод recv () , если это просто абстракция над временным файлом или файлом в кэше IE (или, что еще хуже, потраченным впустую блоком памяти)?

А на какой таймаут ставить? Если я никогда не знаю, насколько велики данные до истечения времени ожидания, тогда как мне решить, что установить значение тайм-аута?

Является ли это ожидаемым поведением, и если да, то есть ли способ получить данные во время их потоковой передачи?

При медленном соединении или с большим файлом вполне вероятно, что большой объем работы может быть выполнено с данными до завершения всей загрузки. В классической повторной реализации HTTP на сокетах Беркли, цикл через вызов recv () предоставит мне данные по мере их поступления, что в конечном итоге является тем, что мне нужно.

Да, я мог бы повторно- напишите реализацию с использованием простых сокетов, но я бы предпочел не тратить время на поддержку всей спецификации HTTP и SSL-шифрования, не говоря уже о поддержке прокси в WinINET.

5
задан Ajay 2 June 2016 в 11:31
поделиться