уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.

fbSl3SFdВ статье “Частичное скачивание web-странички с помощью Synapse” я рассказывал о том, как можно использовать событие сокета OnReadFilter для фильтрации трафика и частичного скачивания странички сайта. Способ достаточно прост, но наравне с простотой имеется также и ряд недостатков о которых я упомянул в конце статьи. Сегодня рассмотрим способы частичного скачивания файлов любого типа. Вы множество раз сталкивались с таким способом скачивания, используя тот же ReGet – когда весь объем файла разбивается на несколько секций и в многопоточном режиме выкачивается с сервера.

У THTTPSend в Synapse есть два свойства в которых можно задавать начало и окончание диапазона данных, которые необходимо получить от сервера, однако есть несколько моментов, которые следует рассмотреть прежде, чем начинать активно использовать байтовые диапазоны в Synapse.

Общие сведения о байтовых диапазонах

HTTP позволяет запросить не всё содержимое ресурса сразу, а только указанный фрагмент. В таком случае речь идёт о частичных GET, возможность их выполнения необязательна для серверов. Частичные GET в основном, как я уже упомянул, используются для докачки файлов и/или быстрого параллельного скачивания в нескольких потоках.

Для того, чтобы запросить с сервера определенный фрагмент ресурса необходимо определить в запросе заголовок Range (диапазон). В этом заголовке мы должны указать: название единицы измерения (bytes – байты), начало и окончание диапазона. При задании заголовка возможно указывать несколько диапазонов через запятую или опускать одну из частей диапазона. Диапазон указывается через символ “-”.

Рассмотрим пример задания диапазонов. Пусть, например, ресурс X имеет размер в 6000 байт. Вот как можно задавать байтовые диапазоны:

1. Произвольный фрагмент:

Range: bytes=3000-5900

range_1 Скачиваем с 3000 по 5900 байт включительно.

2. Один байт:

Range: bytes=3051-3051

range_2

Скачиваем 3051 байт документа.

3. Фрагмент от начала до определенного байта:

Range: –5000

range_3

Скачиваем с 0 по 5000 байт. Эта запись эквивалентна записи для скачивания произвольного фрагмента, т.е. мы могли бы указать диапазон так:

Range: bytes=0-5000

4. Фрагмент, содержащий количество скачиваемых бай от конца ресурса:

Range: bytes=1000-

range_4

Скачиваем последние 1000 байт, т.е. от 5000 до 5999

5. Несколько фрагментов

Range: bytes=1000-, 100-1000

Скачиваем последние 1000 байт, а также фрагмент с 100 по 1000 байт включительно.

range_5

Масштаб на рисунках хромает, но. думаю, смысл улавливается нормально.

Как сказано выше – докачка не обязательно должна поддерживаться сервером. Конечно, большинство серверов её поддерживают, но не все и не всегда. Как понять, что сервер поддерживает докачку файлов?

Провести такую проверку можно опытным путем, отправив, например, такой заголовок на сервер:

Range: bytes=1000-

В этом случае ответ сервера может содержать следующие коды статуса:

  • 200 (Ok)– докачка файлов не поддерживается, а тело запроса будет содержать весь документ
  • 206 (Partial Content) – докачка поддерживается, а тело запроса содержит данные из указанного диапазона
  • 416 (Requested Range Not Satisfiable) – ни один из указанных в заголовке Range диапазонов не является корректным.

 

Теперь посмотрим как реализуется работа с байтовыми диапазонами в Synapse.

Работа с байтовыми диапазонами в Synapse

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

http://webdelphi.ru/wp-content/uploads/downloads/2010/07/Ribbon-Controls-РІ-Delphi-20101.pdf

Для управления диапазонами у THTTPSend имеются два свойства:

  property RangeStart: integer read FRangeStart Write FRangeStart;
  property RangeEnd: integer read FRangeEnd Write FRangeEnd;

 

Первое свойство задает начало диапазона, а второе — его окончание. Посмотрим, какие из пяти приведенных выше вариантов указания заголовка Range мы сможем воспроизвести в Synapse, манипулирую только этими свойствами.

Создадим простенькое приложение, содержащее 3 Edit’а для задания URL и диапазона и кнопку “Скачать”, а также элементы для вывода служебной информации:

part_1

Теперь напишем обработчик OnClick кнопки “Скачать”:

procedure TForm6.Button1Click(Sender: TObject);
var HTTP: THTTPSend;
begin
  HTTP:=THTTPSend.Create;
  try
    HTTP.RangeStart:=StrToInt(edStart.Text);
    HTTP.RangeEnd:=StrToInt(edEnd.Text);
    if HTTP.HTTPMethod('GET',edURL.Text) then
      begin
        lbSize.Caption:=IntToStr(HTTP.Document.Size);
        memHeaders.Clear;
        memHeaders.Lines.Assign(HTTP.Headers);
      end
    else
      ShowMessage(HTTP.ResultString);
  finally
    HTTP.Free;
  end;
end;

 

Теперь попробуйте изменять различным образом значения начала и окончания диапазона и скачать файл с сервера. При этом Вы можете заметить 2 момента:

  1. Synapse может реализовать “на автомате” только 1, 2 и 4 ситуацию работы с байтовыми диапазонами. В принципе этого хватит, чтобы организовать многоопоточную “качалку”. Если нет – никто не запрещает нам вручную вписывать заголовок Range в список Headers
  2. Если задается диапазон 0-10000, то в итоге приходит 10001 байт. Важная мелочь, которая может стоить работоспособности программы

И в заключение, для того, чтобы гарантированно верно “склеивать” отдельно запрошенные фрагменты в один файл необходимо всегда анализировать заголовки Content-Length и Content-Range, возвращаемые сервером. Что касается анализа текстовой части сайта, то о чем я говорил в статье “Частичное скачивание web-странички с помощью Synapse”, то после подробного изучения работы с байтовыми диапазонами я также остался при своем мнении, т.е. использование заголовка Range с целью, например, провести seo анализ сайта приведет к тому, что страница будет качаться целиком с кодом статуса 200. Можете самостоятельно это проверить, например, на моем блоге – сначала скачайте какой-нибудь файл (можно воспользоваться ссылкой выше), а потом попробуйте, используя Range скачать этот пост. Увидите, что во втором случае частичное скачивание не пройдет. Так что для частичного скачивания страниц лучший вариант – это использовать событие OnReadFilter и “мягкая” остановка сокета, через его свойство StopFlag.

Книжная полка

Описание: Рассмотрены практические вопросы по разработке клиент-серверных приложений в среде Delphi 7 и Delphi 2005 с использованием СУБД MS SQL Server 2000, InterBase и Firebird. Приведена информация о теории построения реляционных баз данных и языке SQL. Освещены вопросы эксплуатации и администрирования СУБД.
купить книгу delphi на ЛитРес
Описание: Рассмотрены малоосвещенные вопросы программирования в Delphi. Описаны методы интеграции VCL и API. Показаны внутренние механизмы VCL и приведены примеры вмешательства в эти механизмы. Рассмотрено использование сокетов в Delphi: различные режимы их работы, особенности для протоколов TCP и UDP и др.
купить книгу delphi на ЛитРес
0 0 голоса
Рейтинг статьи
уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
Подписаться
Уведомить о
8 Комментарий
Межтекстовые Отзывы
Посмотреть все комментарии
clHttp
clHttp
13/10/2011 00:03

Что касается анализа текстовой части сайта, то о чем я говорил в статье “Частичное скачивание web-странички с помощью Synapse”, то после подробного изучения работы с байтовыми диапазонами я также остался при своем мнении, т.е. использование заголовка Range с целью, например, провести seo анализ сайта приведет к тому, что страница будет качаться целиком с кодом статуса 200. Не верно, всё зависит от того разрешено ли скачивать частично страницу (разрешает ли сервер), к примеру http://www.wikipedia.org/ тут спокойно можно «скачать» любое количество байт от начала. Вот Ваш сервер видимо не поддерживает частичного скачивания и при этом не сообщает заголовком Accept-Ranges: none что он… Подробнее »

Brunnen Gi
Brunnen Gi
20/03/2012 14:15

Спасибо за статью. А не подскажите как потом склеить? Есть готовая функция или просто методом «открыть файл первый» и «открыть файл второй» из второго дописать содержимое в первый. Или можно как то по проще?

Brunnen Gi
Brunnen Gi
20/03/2012 16:24

Vlad, конечно просто когда уже поварился в этой каше)) Я просто до этого пытался сделать скачивание на WinInet,  но там установка позиции места с которого качать не пашет.  На одном из сайтов посоветовали Синапс заюзать для этих целей. К тому же он еще и ранжирование поддерживает адекватно)) И честно говоря я только сегодня с утра начал примеры на синапсе разбирать!)))) Так что необессудь за мои глупые вопросы ;))  Скажи, мне тогда, как правильно сделать многопоточность? Вот например я захотел в два потока качать. Перенес код в поток. И запустил их с разными диапазонами.  А что если не весь диапазон скачался?… Подробнее »

Brunnen Gi
Brunnen Gi
20/03/2012 19:05

На данный момент времени самый волнующий вопрос это:
Как узнать сколько байт уже закачено после запуска функции HTTP.HTTPMethod(‘GET’, URL), если учесть что запущена она была в потоке?

Brunnen Gi
Brunnen Gi
20/03/2012 19:35

Ммм… ну вот как я сделал.
Я событие на OnStatus привязал к потоку. Т.е. в теории каждый поток будет иметь свой ОнСтатус. Через Синхронизацию можно в принципе его и передавать на форму.
Такой способ правильный? 

Brunnen Gi
Brunnen Gi
20/03/2012 21:00

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