Внимание! Запрещается перепечатка данной
статьи или ее части без согласования с автором. Если вы хотите разместить эту
статью на своем сайте или издать в печатном виде, свяжитесь с автором.
В связи с все большим вниманием, которое привлекает к себе Интернет, все
больше людей становятся заинтересованы в сетевых технологиях. Данная статья
посвящена программированию на 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;
Далее - скачивание указанной странички в указанный файл.
Пример 2. Скачивание указанной URL
в заданный файл
{... Здесь идет заголовок файла и определение формы TForm1 и ее экземпляра Form1}
{В форму нужно поместить кнопку TButton и три поля TEdit. При нажатии
на кнопку вызывается обработчик события OnClick - Button1Click. Перед этим в
первый TEdit нужно ввести адрес URL, во второй - имя файла для заголовка,
а в третий - имя файла для тела странички (html).
НЕ ЗАБУДЬТЕ ПОМЕСТИТЬ В ФОРМУ КОМПОНЕНТ TNMHTTP!}
procedure Button1Click(Sender: TObject);
begin
{Пытаемся получить http-документ}
{Результат надо записать в файлы}
NMHTTP1.InputFileMode := True;
{А здесь указываем в какие именно файлы}
NMHTTP1.Header := Edit2.Text;
NMHTTP1.Body := Edit3.Text;
NMHTTP1.Get(Edit1.Text);
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.
Неплохой пример работы с процессами можно найти в подпапке Demos\Threads
папки, куда Вы установили Delphi.
Замечания по алгоритмам типовых задач
Если Вы собираетесь создать скачивалку сайтов, то Вам необходимо учитывать
следующее (решить следующие проблемы):
Нужно скачивать не только саму страничку в формате HTML, но и все входящие
в нее рисунки (gif, jpg, и т.д.);
в некоторых случаях удобно скачивать не одну страничку, а несколько страниц, ссылки
на которые находятся на первой из скачиваемых страничек. При этом нужно учитывать,
что на страничке могут находиться и ссылки на другие сайты, поэтому необходимо
анализировать скачиваемые ссылки (чтобы случайно не скачать весь Интернет).
Для решения задачи со скачиванием нескольких страничек нужно использовать
рекурсию;
необходимо качественно информировать пользователя о ходе закачки. Т.е. показывать
общее и скачанное количество информации;
после скачивания нужно заменить Интернетовские ссылки на локальные, чтобы
можно было просматривать странички в режиме offline.
Эпилог
В этой статье отображены основные приемы работы с компонентом TNMHTTP в Дельфи.
Если у Вас есть вопросы - скидывайте их мне на E-mail:
snick@mailru.com, а еще лучше - пишите
в конференции этого сайта (Delphi. Общие вопросы), чтобы и другие пользователи
смогли увидеть Ваш вопрос и попытаться на него ответить!
Замечу, что TNMHTTP - не единственный компонент, релизующий доступ по протоколу
HTTP. Есть и его аналоги с более расширенными возможностями, например, набор
компонентов ICS (Internet Component Suite), в состав которого входит даже компонент
FTPServer, позволяющий легко запрограммировать свой собственный сервер FTP для
Windows. Этот набор можно скачать на сайте
Delphi Super Page.