реализация менеджера загрузки, который поддерживает возобновление - PullRequest
11 голосов
/ 04 апреля 2009

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

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

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

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

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

Ответы [ 7 ]

7 голосов
/ 04 апреля 2009

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

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

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

Content-Range usu. выглядит так: Content-Range: bytes 21010-47000/47022, то есть байты, начало-конец / итог.

Проверьте HTTP spec для деталей, особенно разделы 14.5, 14.16 и 14.35

4 голосов
/ 04 апреля 2009

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

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

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

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

3 голосов
/ 04 апреля 2009

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

Размер куска

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

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

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

В памяти и файлах

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

3 голосов
/ 04 апреля 2009

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

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

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

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

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

2 голосов
/ 29 июня 2010

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

0 голосов
/ 14 мая 2010

для поддержки возобновления паузы посмотрите на этот простой пример Простой менеджер загрузок в Qt с поддержкой puase / resume

0 голосов
/ 04 апреля 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...