Внедрение диспетчера загрузки, который поддерживает возобновление

Я собираюсь написать небольшой менеджер загрузок на С++, который поддерживает возобновление (и несколько подключений для загрузки).

Из информации, которую я собрал до сих пор, при отправке HTTP-запроса мне нужно добавить поле заголовка с ключом "Range" и значением "bytes = startoff-endoff". Затем сервер возвращает ответ http с данными между этими смещениями.

Итак, примерно то, что я имею в виду, это разделить файл на количество разрешенных подключений на файл и отправить HTTP-запрос на разделенную часть с соответствующим "диапазоном". Так что, если у меня есть файл размером 4 МБ и 4 разрешенных соединения, я бы разделил файл на 4 и пропустил 4 http-запроса, каждый из которых имел соответствующее поле "Диапазон". Реализация функции возобновления будет включать в себя запоминание того, какие смещения уже загружены и просто не запрашивать их.

  • Это правильный способ сделать это?
  • Что делать, если веб-сервер не поддерживает возобновление? (думаю, он будет игнорировать "Range" и просто отправить весь файл).
  • При отправке HTTP-запросов следует ли указывать в диапазоне весь размер разделенного? Или, может быть, спросите более мелкие куски, скажем, 1024k за запрос?
  • При чтении данных следует записать его непосредственно в файл или сделать какую-то буферизацию? Я думаю, это может быть расточительно писать небольшие куски.
  • Должен ли я использовать файл с отображением памяти? Если я правильно помню, он рекомендовал для частых чтений, а не для записи (я мог ошибаться). Это память разумная? Что делать, если у меня есть несколько загрузок одновременно?
  • Если я не использую файл с отображением памяти, должен ли я открыть файл для разрешенного соединения? Или когда нужно писать в файл просто искать? (если бы я использовал файл с отображением памяти, это было бы очень просто, так как я мог просто иметь несколько указателей).

Примечание. Я, вероятно, буду использовать Qt, но это общий вопрос, поэтому я оставил код из него.

Ответ 1

Относительно запроса/ответа:

для запроса Range-d вы можете получить три разных ответа:

206 Partial Content - возобновление поддерживается и возможно; проверьте заголовок Content-Range для размера/диапазона ответа
200 OK - байтовые диапазоны ( "возобновление" ) не поддерживаются, весь ресурс ( "файл" ) следует за 416 Requested Range Not Satisfiable - неправильный диапазон (предыдущий EOF и т.д.)

Контент-диапазон. выглядит так: Content-Range: bytes 21010-47000/47022, то есть байты start-end/total.

Подробнее о Спецификация HTTP, особенно. разделы 14.5, 14.16 и 14.35

Ответ 2

Я не эксперт на С++, однако однажды я сделал приложение .net, которое нуждалось в подобной функциональности (планирование загрузки, поддержка резюме, приоритизация загрузок)

я использовал компонент microsoft bits (Background Intelligent Transfer Service), который был разработан в c. Windows update также использует BITS. Я пошел на это решение, потому что не думаю, что я достаточно хорошо программист, чтобы написать что-то из этого уровня: -)

Хотя я не уверен, что вы можете получить код BITS - я думаю, вам стоит просто взглянуть на его документацию, которая может помочь вам понять, как они реализовали ее, архитектуру, интерфейсы и т.д.

Вот он - http://msdn.microsoft.com/en-us/library/aa362708(VS.85).aspx

Ответ 3

Помимо отслеживания того, что было смещениями, обозначающими начало ваших сегментов и длину каждого сегмента (если вы не хотите вычислить, что при возобновлении, которое включало бы сортировку списка смещений и вычисление расстояния между двумя из них), вы захотите чтобы проверить заголовок Accept-Ranges ответа HTTP, отправленного сервером, чтобы убедиться, что он поддерживает использование заголовка Range. Лучший способ указать диапазон: "Диапазон: байты = START_BYTE-END_BYTE", а диапазон, который вы запрашиваете, включает START_BYTE и байт END_BYTE, состоящий из (END_BYTE-START_BYTE) +1 байта.

Запрос микросхем - это то, о чем я бы советовал, поскольку вы можете быть внесены в черный список с помощью правила брандмауэра, чтобы блокировать потоки HTTP. В общем, я бы предложил, чтобы вы не делали куски размером менее 1 МБ и не делали более 10 кусков. В зависимости от того, какой контроль вы планируете использовать при загрузке, если у вас есть элемент управления уровнем сокета, вы можете рассматривать запись только один раз каждые 32 Кбит или асинхронно записывать данные.

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

О работе с кусками вы можете просто создать несколько файлов - по одному на сегмент, опционально предустановить дисковое пространство, заполняющее файл с таким количеством \x00, как размер куска (preallocating может сэкономить когда-нибудь, когда вы пишете во время загрузите, но запустите загрузку медленнее), а затем, наконец, просто напишите все куски последовательно в финальный файл.

Одна вещь, о которой вы должны остерегаться, заключается в том, что на нескольких серверах есть макс. ограничение одновременных соединений, и вы не узнаете его заранее, поэтому вы должны быть готовы обрабатывать HTTP-ошибки/таймауты и изменять размер кусков или создавать очередь блоков в случае, если вы создали больше кусков, чем Максимум. соединения.

Ответ 4

Я не могу ответить на все ваши вопросы, но вот мой подход к двум из них.

Размер блока

Есть две вещи, которые вы должны учитывать размер блока:

  • Чем меньше, тем больше накладных вы получаете форму отправки HTTP-запроса.
  • С большими кусками вы рискуете повторно загрузить одни и те же данные дважды, если одна загрузка не удалась.

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

В памяти против файлов

Вы должны записать куски данных в буфер памяти, а затем, когда он будет полностью записан на диск. Если вы собираетесь загружать большие файлы, это может быть проблематичным для ваших пользователей, если они исчерпаны из ОЗУ. Если я правильно помню, что в IIS хранятся запросы размером менее 256 кб в памяти, на диске будет записано что-либо большее, вы можете захотеть рассмотреть аналогичный подход.

Ответ 5

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

Ответ 6

Мне кажется, вы хотели бы ограничить размер загружаемого фрагмента. Большие куски могут заставить вас повторить загрузку данных, если соединение прервано ближе к концу части данных. Специально проблема с более медленными соединениями.