Я пишу утилиту загрузки файлов с помощью 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.Из MSDN
Функция InternetOpenUrl : Функция InternetOpenUrl анализирует строку URL-адреса, устанавливает соединение с сервером и подготавливает к загрузке данных, идентифицированных URL-адресом. Затем приложение может использовать InternetReadFile [...] для получения данных URL.Из 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.