Работа с HTTP протоколом в Delphi
Работа с HTTP протоколом в Delphi
В
связи с все большим вниманием, которое привлекает к себе Интернет, все больше
людей становятся заинтересованы в сетевых технологиях. Данная статья посвящена
программированию на Borland Delphi с использованием одного из самых популярных
Интернет-протоколов - HTTP.
А
именно, здесь мы рассмотрим компонент TNMHTTP (NetMasters HTTP), который можно
обнаружить на вкладке FastNet палитры компонентов Дельфи.
Начнем
с теории. Если Вы уже знаете, что такое HTTP и зачем он нужен, то пропустите
следующий раздел.
Зачем нужен HTTP
Итак,
где же используется HTTP? Если Вы хотя бы чуть-чуть заглядывали на
Интернет-странички и встречались с термином Web, то наверняка обратили внимание
на то, что адреса страничек, как правило, начинаются с http://. Протокол HTTP
(HyperText Transfer Protocol) позволяет принимать и посылать не только
гипертекстовые документы (типа html), но и любые другие (тексты (txt),
изображения (gif, jpg), и т.д.). Ниже приведены типовые задачи, для выполнения
которых необходимо использовать HTTP:
Браузеры
- программы, позволяющие просматривать Интернет-странички;
Скачивальщики
- программы, позволяющие скачивать из Интернета странички, рисунки и другие
документы;
Чаты
- программы, позволяющие общаться по сети. Часто документы HTTP используются
для хранения сообщений (как, например, в конференциях).
-
Это лишь список некоторых из стандартных направлений программирования с
использованием HTTP. Вы можете применять этот протокол для любых своих целей.
Например, автоматические системы обновления данных, посылка запросов в
Интернетовские базы, и еще множество всяческих других возможностей!
Краткое описание свойств, методов и событий
Ниже
приведена таблица, содержащая наиболее краткое описание основных свойств,
методов и событий компонента TNMHTTP:
Свойства
Body
- строка, содержащая либо путь к файлу, в который будет записано тело
http-документа (если св-во InputFileMode равно True), либо непосредственно само
тело (если св-во InputFileMode равно False). Тип: string;
Header
- строка, содержащая либо путь к файлу, в который будет записан заголовок
http-документа (если св-во InputFileMode равно True), либо непосредственно сам
заголовок (если св-во InputFileMode равно False). Тип: string;
HeaderInfo
- структура, содержащая различную информацию о http-документе (подробней см. в
help-файле). Тип: THeaderInfo;
InputFileMode
- тип записи результата. Значение True - запись в файлы, указанные в свойствах
Body и Header, False - запись в сами эти свойства. Тип: Boolean;
OutputFileMode
- тип отсылаемых данных (методами Put, Post и Trace). Значение True - данные
для отправки содержатся в файлах, указанных при вызове этих методов, а False -
в самих аргументах этих методов. Тип: Boolean;
Далее
некоторые свойства, унаследованные от TPowerSock:
BytesRecvd,
BytesSent, BytesTotal - количество отправленных, принятых и общее количество
байтов соотвественно. Тип: LongInt;
Connected
- показывает, установленно ли в данный момент соединение. Тип: Boolean;
BeenCanceled
- показывает, было ли прервано соединение с сервером. Тип: Boolean;
Host
- строка, содержащая хост-имя удаленного компьютера. Заполнять не надо, так как
это свойство устанавливается автоматически при вызове методов Get, Put, Post и
т.д. Тип: string. Port - Integer, содержащий порт удаленного компьютера
(заполняется тоже автоматически);
TimeOut
- таймаут в миллисекундах. Тип: Integer;
Еще
есть множество свойств, но я пока остановлюсь на уже перечисленных. За
дополнительной информацией обращайтесь к help-у по Дельфи.
Методы
Get(URL:
string) - посылает запрос на указанный URL. Данные после выполнения этого
запроса записываются в файлы или в сами свойства Body и Header (в зависимости
от значения свойства InputFileMode);
Head(URL:
string) - посылает запрос на указанный URL. Данные после выполнения этого
запроса записываются в файл или в само свойство Header (в зависимости от
значения свойства InputFileMode). В отличие от метода Get, при вызове Head
запрос отсылается только на заголовок http-документа;
Post(URL,
PostData: string) - посылает запрос на изменение http-документа (с адресом URL)
на данные, содержащиеся в параметре PostData. Если OutputFileMode равен True,
то в PostData должен содержаться путь к файлу, содержащему нужные данные.
Put(URL,
PutData: string) - посылает запрос на создание http-документа (с адресом URL),
содержащего данные, переданные в параметре PutData. Если OutputFileMode равен
True, то в PostData должен содержаться путь к файлу, содержащему нужные данные.
Trace(URL,
TraceData: string) - посылает запрос на получение отладочных данных (для
отладки соединения с HTTP-сервером). Данные для запроса нужно указать в
параметре TraceData. Если OutputFileMode равен True, то в TraceData должен
содержаться путь к файлу, содержащему нужные данные.
Delete(URL:
string) - посылает запрос на удаление http-документа (с адресом URL).
Далее
некоторые методы, унаследованные от TPowerSock:
Abort
и Cancel - прерывают соединение и обмен данными;
Disconnect
- отсоединение от HTTP-сервера;
События
OnAuthenticationNeeded
- возникает, когда сервер требует указания имени пользователя и пароля. В
обработчике этого события (если оно возникнет) Вы должны ответить серверу,
запонив нужными значениями соответствующие переменные. Примечание: Перед
установлением соединения можно сразу заполнить поля UserID и Password в
свойстве HeaderInfo;
OnAboutToSend
- возникает, когда компонент TNMHTTP собирается отправлять данные (запрос). В
обработчике этого события можно заполнить дополнительной информацией свойство
SendHeader;
OnFailure
- возникает, когда текущая операция завершилась неудачно, т.е. произошла
ошибка;
OnRedirect
- возникает, сервер переадресовал ссылку с указанной URL на другую ссылку.
Установив параметр handled в значение True можно запретить переадресацию и остановиться
на запрошенной URL. Значение по умолчанию - False;
OnSuccess
- возникает, когда текущая операция завершилась успешно, т.е. запрос был
выполнен без ошибок;
Далее
некоторые методы, унаследованные от TPowerSock:
OnConnect
- возникает, когда соединение с сервером успешно установлено;
OnDisconnect
- возникает, когда соединение с сервером завершено;
OnConnectionFailed
- возникает, когда соединение с сервером установить не удалось;
OnError
- возникает, когда последняя операция была завершена с ошибкой;
OnHostResolved
- возникает, когда от DNS получен IP-адрес указанного хоста;
OnInvalidHost
- возникает, когда DNS вернул ошибку при попытке определить IP-адрес указанного
хоста;
OnPacketRecvd
- возникает, когда значения свойств BytesRecvd и BytesTotal изменены, т.е. была
принята новая порция данных от сервера;
OnPacketSent
- возникает, когда значения свойств BytesSent и BytesTotal изменены, т.е. была
отправлена новая порция данных на сервер;
OnStatus
- возникает, когда статус компонента был изменен (для обновления визуального
оповещения пользователя);
Практика и примеры
Ну
а теперь приступим к самому главному методу изучения - на примерах.
И
самый первый пример - программа, позволяющая определить, существует ли заданный
URL:
Пример
1. Проверка существования указанной URL
{...
Здесь идет заголовок файла и определение формы TForm1 и ее экземпляра Form1}
{В
форму нужно поместить кнопку TButton и одно поле TEdit. При нажатии на
кнопку
вызывается обработчик события OnClick - Button1Click. Перед этим в
TEdit
нужно ввести адрес URL. НЕ ЗАБУДЬТЕ ПОМЕСТИТЬ В ФОРМУ КОМПОНЕНТ TNMHTTP!}
procedure Button1Click(Sender:
TObject);
begin
{Пытаемя получить заголовок}
NMHTTP1.Head(Edit1.Text);
{Если
URL неверный, то здесь выскочит ошибка}
end;
Следующий
пример - скачивание сразу нескольких URL одновременно. Надо заметить, что
многие программисты пренебрегают многозадачностью Windows (неважно, как она
реализована, речь сейчас не об этом). В Дельфи очень легко создавать отдельные,
подчиненные Вашей программе процессы (а точнее - потоки) с помощью базового
класса TThread. Но об этом мы поговорим в другой раз (в другой статье).
Пример
3. Одновременное скачивание указанных URL в заданный каталог
//
Здесь идет заголовок файла и определение формы TForm1 и ее экземпляра Form1
//
Описание класса отдельного процесса
type
THTTPThread
= class(TThread)
private
{Для
каждого процесса - создаем свой компонент TNMHTTP}
FHTTP:
TNMHTTP;
protected
//
Execute вызывается при запуске процесса; override - заменяем
//
существующую процедуру базового класса TThread
procedure
Execute; override;
//
DoWork - созданная нами функция, выполнение которой синхронизируется в Execute
procedure
DoWork;
public
//
URL - созданная нами строка, указывающая процессу, какой URL ему нужно скачать
URL:
string;
end;
//
В форму нужно поместить три кнопки TButton, одно поле TEdit и один список
//
TListBox. При нажатии на кнопку Button1 вызывается обработчик события
//
OnClick - Button1Click. Перед этим в TEdit нужно ввести путь к каталогу, в
//
котором будут храниться скачанные файлы, а ListBox1 нужно заполнить списком
//
URL-ов для скачивания (с помощью кнопок Add (Button2) и Delete (Button3)).
procedure
TForm1.Button3Click(Sender: TObject);
begin
{Удаление
выделенного URL из списка}
if ListBox1.ItemIndex >= 0 then
ListBox1.Items.Delete(ListBox1.ItemIndex);
end;
procedure
TForm1.Button2Click(Sender: TObject);
var s: string;
begin
{Добавление URL в список}
s := InputBox('Добавить','Введите URL:','');
if s '' then
ListBox1.Items.Add(s);
end;
procedure
TForm1.Button1Click(Sender: TObject);
var i: Integer;
begin
{Проверка
на существование каталога}
if Length(Edit1.Text) > 0 then
if not DirectoryExists(Edit1.Text)
then
MkDir(Edit1.Text);
{Далее
идет создание для каждого URL в списке своего процесса}
for i := 0 to ListBox1.Items.Count-1
do begin
with THTTPThread.Create(True) do
begin
{Создаем
приостановленную задачу, указываем ей ее URL и запускаем ее}
URL := ListBox1.Items[i];
Resume;
end;
end;
end;
// Операторы процесса THTTPThread
procedure THTTPThread.Execute;
begin
//
Делаем так, чтобы каждый процесс выполнялся одновременно с другими (синхронизация)}
Synchronize(DoWork);
end;
procedure THTTPThread.DoWork;
var i: Integer;
begin
{Создаем компонент TNMHTTP}
FHTTP := TNMHTTP.Create(Form1);
{Результат
надо записывать в файлы}
FHTTP.InputFileMode := True;
{Подбираем
имена для файлов}
i := 1;
while
FileExists(Form1.Edit1.Text+'page'+IntToStr(i)+'.htm') do
Inc(i);
{Указываем,
в какие именно файлы класть результат}
FHTTP.Body := Form1.Edit1.Text+'body'+IntToStr(i)+'.htm';
FHTTP.Header :=
Form1.Edit1.Text+'header'+IntToStr(i)+'.txt';
{Пытаемся
послать запрос}
FHTTP.Get(URL);
{Перед
завершением процесса не забываем освободить память из-под компонента}
FHTTP.Free;
end;
ПРИМЕЧАНИЕ:
Чтобы завершить некоторый процесс (Thread), нужно вызвать метод Terminate
класса этого процесса. Приостановить процесс можно оператором Suspend, а
продолжить выполнение - Resume. Также можно настроить приоритет каждого
отдельного процесса через свойство Priority.
Неплохой
пример работы с процессами можно найти в подпапке DemosThreads папки, куда Вы
установили Delphi.
Замечания
по алгоритмам типовых задач
Если
Вы собираетесь создать скачивалку сайтов, то Вам необходимо учитывать следующее
(решить следующие проблемы):
Нужно
скачивать не только саму страничку в формате HTML, но и все входящие в нее
рисунки (gif, jpg, и т.д.);
в
некоторых случаях удобно скачивать не одну страничку, а несколько страниц,
ссылки на которые находятся на первой из скачиваемых страничек. При этом нужно
учитывать, что на страничке могут находиться и ссылки на другие сайты, поэтому
необходимо анализировать скачиваемые ссылки (чтобы случайно не скачать весь
Интернет). Для решения задачи со скачиванием нескольких страничек нужно
использовать рекурсию;
необходимо
качественно информировать пользователя о ходе закачки. Т.е. показывать общее и
скачанное количество информации;
после
скачивания нужно заменить Интернетовские ссылки на локальные, чтобы можно было
просматривать странички в режиме offline.
Список литературы
Для
подготовки данной работы были использованы материалы с сайта http://www.hostmake.ru/