Вы можете получить практически такой же эффект в локальной сети с http-прокси. Прокси-сервер загружает весь файл медленно по глобальной сети, а затем быстро представляет файл на ПК через локальную сеть. В моем случае задержка до получения первых данных составила 20 секунд, а затем весь файл прибывает почти мгновенно.

у утилиту загрузки файлов, используя WinINET, и заметил (особенно при больших загрузках), что WinINETInternetOpenUrl() Вызов возвращается только после того, как весь 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)
{
  // <only gets here after entire download is complete>

  InternetCloseHandle(hUrl);
}
InternetCloseHandle(hInt);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Ответы на вопрос(1)

Ваш ответ на вопрос