Пример работы с компонентами Indy UDP (server, client) на Delphi. Delphi-приложение отправляющее данные на сервер методом POST (Indy)

Главная / Операционные системы

Введение в Indy

Введение в Indy
Автор: Chad Z. Hower
Домашняя страница: http://www.atozedsoftware.com
Перевод: Анатолий Подгорецкий
Вступительное слово
Я написал эту статью, когда текущей версией была Indy 8.0. Многое их этой статьи применимо и очень полезно в следующих версиях Indy. Если вам понравилась данная статья, и вы желаете прочитать более подробные статьи, то обратите внимание на книгу Indy in Depth.
Indy работает в блокирующем режиме
Indy использует работу с сокетами в блокирующем режиме. Блокирующий режим подобен чтению-записи файла. При чтении данных или записи функция не возвращает управления до окончания операции. Отличие от работы с файлами состоит в том, вызов может быть более долгим, поскольку запрошенных данных еще нет, это зависит скорости, с какой работает ваша сеть или модем.
Для примера, просто производится вызов метода, и ожидание пока не будет возвращено управление в точку вызова. Если вызов был успешный, то управление будет возвращено из метода, при ошибке будет возбуждено исключение.
Блокирующий режим это не смертельно
Из-за блокирующего режима мы неоднократно были биты нашими противниками, но блокирующий режим не является дьяволом.
Проблема появилась после портирования Winsock в Windows. В Юниксе типично проблема решалась за счет раздвоения (похоже на много поточность, но за счет отдельных процессов вместо потоков). Юникс клиенты и демоны (daemons) должны были раздваиваться процессы, которые должны выполняться и использовать блокирующий режим. Windows 3.x не мог распараллеливаться и не поддерживал много поточность. Использование блокирующего интерфейса замораживало пользовательский интерфейс и делало программы не реагирующими. Поэтому к WinSock были добавлены не блокирующие режимами, позволяя Windows 3.x с его ограничениями использовать Winsock без блокирования основного и единственного потока программы. Это потребовало другого программирования, Microsoft и другие страстно поносили блокирующие режимы, что бы скрыть недостатки Windows 3.x.
Затем пришла Win32, которая смогла поддержать много поточность. Но к этому моменту мозги уже были запудрены (то есть разработчики считали блокирующие сокеты порождением дьявола), и уже было тяжело изменить содеянное. По этому поношение блокирующих режимов продолжается.
В реальности в Юникс есть только блокирующие сокеты. Блокирующие сокеты также имеют и свои преимущества, и они намного лучше, для много поточности, безопасности и других аспектов. Некоторые расширения была добавлены и в Юникс для не блокирующих сокетов. Тем не менее, они работают совсем по другому, чем в Windows. Они также нестандартны и не очень распространены. Блокирующие сокеты в Юниксе используются почти во всех случаях, и будут и далее использоваться.
Достоинства блокирующего режима·Проще программировать - Блокирующие режимы проще программировать. Весь пользовательский код может находиться в одном месте и выполняться в естественном, последовательном порядке. ·Проще перенос в Юникс - Поскольку Юникс использует блокирующие сокеты, переносимый код написать в данном случае проще. Indy использует этот факт для написания единого кода. ·Удобнее работать с потоками - Поскольку у блокирующих сокетов последовательность приобретена по наследственности, поэтому их очень просто использовать в потоках.
Недостатки блокирующего режима·Пользовательский интерфейс замораживается в клиентах - Вызов блокирующего сокета не возвращает управления, пока не выполнит свою задачу. Когда такой вызов делается в главном потоке приложения, приложение не может обрабатывать пользовательские сообщения. Из-за этого пользовательский интерфейс замораживается, не обновляются окна, и другие сообщения не могут быть обработаны пока управление не будет возвращено из блокирующего сокета.
Компонент TIdAntiFreeze
В Indy имеется специальный компонент, который решает проблему замораживания пользовательского интерфейса. Просто добавьте один компонент TIdAntiFreeze куда ни будь в своем приложении, и вы сможете выполнять блокирующие вызовы без замораживания пользовательского интерфейса.
TIdAntiFreeze работает по внутреннему таймеру вне стека вызовов и вызывает Application.ProcessMessages по окончанию таймаута. Внешние вызовы к Indy продолжают оставаться блокирующими и поэтому работают точно также как и без использования компонента TIdAntiFreeze. Использование TIdAntiFreeze позволяет получить все преимущества блокирующих сокетов, без из недостатков.
Кодовые потоки (Threading)
С блокирующими сокетами почти всегда используются кодовые потоки. Не блокирующие сокеты также могут использовать потоки, но это требует некоторой дополнительной обработки и их преимущества в этом случае теряются, по сравнению с блокирующими сокетами.
Достоинства потоков·Настройка приоритетов - Приоритеты отдельных потоков могут быть настроены. Это позволяет выполнять выделять отдельным задачам больше или меньше процессорного времени. ·Инкапсуляция - Каждое соединение может содержать некоторое подобие интерфейса с другим соединением. ·Безопасность - Каждый поток может иметь различные атрибуты безопасности. ·Несколько процессоров - дает преимущество на системах с несколькими процессорами. ·Не нужна сериализация - предоставляет полную конкурентность. Без много поточности все запросы должны быть обработаны в одном потоке. Поэтому каждая задача должна быть разбита на небольшие куски, чтобы она могла работать быстро. Пока выполняется один блок, все остальные вынуждены ожидать его окончания. По окончанию одного блока выполняется следующий и так далее. С многопоточностью каждая задача может быть запрограммирована как одно целое и операционная система распределяет время между всеми задачами.
Опрос потоков
Создание и уничтожение потоков очень интенсивно использует ресурсы. Это особо тяжелая задача для серверов, которые имеют коротко живущие соединения. Каждый сервер создает поток, использует его короткое время и затем уничтожает. Это приводит к очень частому созданию и удалению потоков. Примером этого является Веб сервер. Посылается одиночный запрос, и возвращается простой ответ. При использовании браузера, при просмотре какого либо Веб сайта, могут происходить сотни соединений и отсоединений
Опрос потоков может исправить эту ситуацию. Вместо создания и уничтожения потоков по требованию, потоки выбираются из списка неиспользуемых, но уже созданных потоков, из пула. Когда поток уже не нужен, он возвращается в пул, вместо его уничтожения. Потоки в пуле помечаются как неиспользуемые и поэтому они не жрут процессорное время. Для еще большего улучшения потоки могут динамически подстраиваться под текущие нужды системы.
Indy поддерживает опрос потоков. Пул потоков в Indy доступен через компонент TIdThreadMgrPool.
Множество потоков
Для сильно нагруженного сервера может потребоваться сотни или даже тысячи потоков. Есть общее убеждение, что сотни и тысячи потоков могут убить вашу систему. Это неверное убеждение.
В большинстве серверов потоки находятся в ожидании данных. Во время ожидания при блокирующем вызове поток неактивен. В сервере с 500 потоков только 50 могут быть активны в одно и тоже время.
Количество потоков, которые запущены на вашей системе, может удивить вас. При минимальном количестве запущенных серверов и указанными запущенными приложениями моя система имеет 333 созданных потоков, даже при 333 потоках процессор нагружен только на 1%. Сильно нагруженный сервер IIS (Microsoft Internet Information Server) может создать сотни и тысячи потоков.
Потоки и глобальные секции
При нескольких потоках Вы должны обеспечить целостность данных при доступе к ним. Это может оказаться сложным для программистов, не работавших с потоками. Но, как правило, большинству серверов не требуется использование глобальных данных. Большинство серверов выполняет изолированные функции. Каждый поток выполняет свою изолированную задачу. Глобальные секции чтения/записи это особенность многих многопоточных приложений, но не типичны для серверов.
Методология Indy
Indy отличается от других Winsock компонент, к которым Вы привыкли. Если вы работали с другими компонентами, то лучшим решением будет забыть как они работают. Многие другие компоненты используют не блокирующие (асинхронные) вызовы и работают асинхронно. Им требуется реагировать на события, создавать машину состояния и часто выполнять циклы ожидания.
Например, с другими компонентами, когда вы вызывает соединение вы должны или ждать возникновение события соединения или в цикле ожидать когда свойство покажет что соединение произошло. С Indy вы можете вызвать метод Connect, и ожидать возврата из него. Возврат будет произведен в случае успешного соединения или возбуждения исключения в случае проблемы. Поэтому работа с Indy очень похоже на работу с файлами. Indy позволяет разместить весь ваш код в одном месте, вместо размазывания по разным событиям. В дополнение, Indy очень прост и наиболее удобен при работе с потоками.
Насколько Indy отличается
Краткий обзор·Используются блокирующие вызовы ·Не ориентирован на события - события есть, но они используются для информационных нужд, и реально не требуются. ·Разработан для потоков - Indy разработан для потоков, тем не менее, может использоваться и без потоков. ·Последовательное программирование
Подробное рассмотрение
Indy не только использует блокирующие вызовы (синхронные) но еще и работает так. Типичная сессия в Indy выглядит так:
with IndyClient do begin
Connect; Try
// Do your stuff here
finally Disconnect; end;
end;
С другими компонентами это выглядит так:
procedure TFormMain.TestOnClick(Sender: TComponent);
begin
with SocketComponent do begin
Connect; try
while not Connected do begin
if IsError then begin
Abort;
end;

OutData:= "Data To send";
while length(OutData) > 0 do begin
Application.ProcessMessages;
end;
finally Disconnect; end;
end;
end;
procedure TFormMain.OnConnectError;
begin
IsError:= True;
end;
procedure TFormMain.OnRead;
var
i: Integer;
begin
i:= SocketComponent.Send(OutData);
OutData:= Copy(OutData, i + 1, MaxInt);
end;
Многие компоненты не очень хорошо выполняют работу по изоляции программиста от стека. Многие компоненты вместо изоляции пользователя от сложностей стека просто оставляют его наедине с ним или предоставляют обертку над стеком.
Особый путь Indy
Indy разработан с нуля быть многопоточным. Построение серверов и клиентов в Indy подобно построению серверов и клиентов в Юниксе. Юникс приложения обычно вызывают стек напрямую с минимумом или совсем без слоя абстрагирования.
Обычно Юникс сервера имеют один или несколько слушающих процессов, которые следят за входящими запросами клиентов. Для каждого клиента, которого требуется обслужить, создается новый процесс. Это делает простым программирование, каждый процесс только для одного клиента. Каждый процесс запускается в своем собственном контексте безопасности, который задается слушающим процессом или процессом, базирующимся на существующих правах, идентификации или других вещах.
Indy серверы работают почти аналогичным образом. Windows в отличие от Юникс не может хорошо размножать процессы, но зато хорошо работает с потоками. Indy сервера создают отдельный поток для каждого соединения клиента.
Indy сервера назначают слушающий поток, который отделен от главного кодового потока программы. Слушающий поток слушает входящие запросы от клиентов. Для каждого клиента, которому отвечает, создается новый поток для обслуживания клиента. Соответствующие события затем обслуживаются в контексте данного потока.
Обзор клиентов Indy
Indy разработан чтобы предоставить очень высокий уровень абстракции. Запутанность и детализация TCP/IP стека скрывается от программиста.Обычно типичная сессия клиента в Indy выглядит следующим образом:
with IndyClient do begin
Host:= "zip.pbe.com"; // Host to call
Port:= 6000; // Port to call the server on
Connect; Try
// Do your stuff here
finally Disconnect; end;
end;
Обзор серверов Indy
Indy серверные компоненты создают слушающий поток, который изолирован от главного кодового потока программы. Слушающий поток прослушивает входящие запросы от клиентов. Для каждого клиента, которому отвечает, создается новый поток для обслуживания клиента. Соответствующие события затем обслуживаются в контексте данного потока.

Практические примеры
Следующие примеры должны помочь вам начать работать с компонентами для простого использования, но для того, что бы продемонстрировать примеры сделаны как простые приложения. Некоторые проекты сделаны для демонстрации различных ситуаций. Данные примеры также доступны для загрузки как zip файлы.
Примечание от переводчика: ссылка на сайте не рабочая.
Пример 1 - Проверка почтового индекса
Первый проект сделан максимально простым. Поиск по почтовому индексу, клиент запрашивает сервер какому городу и штату принадлежит указанный индекс.
Для тех кто живет за пределами США и не знают что такое zip код, это почтовый код, который указывает место доставки. Почтовые коды состоят из 5 цифр.
Протокол
Первый шаг в построении сервера и клиента - это разработка протокола. Для стандартных протоколов это определяется соответствующим RFC. Для почтового индекса протокол определяется ниже.
Большинство протоколов обмена работают в текстовом режиме. Обмен означает, что передается команда, а в ответ состояние и возможно данные. Протоколы не ограничиваются обменом, но все равно используется простой текст. Протокол определения почтового индекс также текстовый. Простой текст делает протоколы простыми для отладки и позволяет общаться различным языкам программирования и операционным системам.
После соединения, сервер посылает приветственное сообщение, затем принимает команду. Эта команда может быть "ZipCode x" (Где x это почтовый индекс) или "Quit". В ответ на команду ZipCode посылается ответ в виде одной строки с ответом или пустая строка если код не найден. Команда Quit заставляет сервер разорвать соединение. Сервер может принять несколько команд, прежде, чем будет послана команда Quit.
Исходный код сервера

unit ServerMain;

interface

uses

type

TformMain = class (TForm)

IdTCPServer1: TIdTCPServer;

procedure FormCreate(Sender: TObject ) ;

procedure FormDestroy(Sender: TObject ) ;

procedure IdTCPServer1Connect(AThread: TIdPeerThread) ;

private

ZipCodeList: TStrings;

public

end ;

FormMain: TformMain;

implementation

{R *.DFM}

procedure TformMain.IdTCPServer1Connect (AThread: TIdPeerThread) ;

begin

AThread.Connection .WriteLn ("Indy Zip Code Server Ready." ) ;

end ;

SCommand: string ;

begin

SCommand:= ReadLn ;

end ;

end ;

end ;

procedure TformMain.FormCreate (Sender: TObject ) ;

begin

ZipCodeList:= TStringList.Create ;

ZipCodeList.LoadFromFile (ExtractFilePath (Application.EXEName ) + "ZipCodes.dat" ) ;

end ;

procedure TformMain.FormDestroy (Sender: TObject ) ;

begin

ZipCodeList.Free ;

end ;

end .

Единственные части в проекте, специфические для Indy, это компонент IdTCPServer1, методы IdTCPServer1Connect и IdTCPServer1Execute.
На форме размещен компонент IdTCPServer1 типа TIdTCPServer. Изменены следующие свойства: ·Active = True - После старта приложения сервер прослушивает. ·DefaultPort = 6000 - Значение порта для данного проекта. Сервер слушает запросы клиента на этом порту.
Метод IdTCPServer1Execute связан с событием OnExecute сервера. Событие OnExecute возбуждается после того, как соединение клиента акцепцировано. Событие OnExecute отличается от других известных вам событий. OnExecute выполняется в контексте потока. Событие потока вызывается и ему передается аргумент AThread, переданный в метод. Это важно, поскольку множество событий OnExecute может выполняться в одно и тоже время. Это сделано для того, чтобы сервер мог работать без создания нового компонента. Есть также методы, которые могут быть перекрыты при построении наследников.
Событие OnConnect вызывается после того, как соединение было акцепцировано и поток для него был создан. В данном сервере это используется для посылки приветственного сообщения клиенту. При желании это также может быть выполнено и в событии OnExecute.
Событие OnExecute может быть возбуждено несколько раз, пока соединение не будет разъединено или потеряно. Этим устраняется необходимость проверять соединение, на предмет разъединения или потери в цикле внутри события.
IdTCPServer1Execute использует две базовые функции, ReadLn и WriteLn. ReadLn читает строку из соединения, а WriteLn посылает строку в соединение.
sCommand:= ReadLn;
Выше приведенный код принимает строку от клиента и помещает ее в локальную строковую переменную sCommand.

if SameText (sCommand, "QUIT" ) then begin

end else if SameText (Copy (sCommand, 1 , 8 ) , "ZipCode " ) then begin

WriteLn (ZipCodeList.Values [ Copy (sCommand, 9 , MaxInt) ] ) ;

end ;


Далее sCommand проверяется на допустимые команды.
Если команда "Quit" то производится Разъединение. Никакое чтение или запись не разрешены после разъединения. После окончания события, слушающий поток более его не вызывает, а очищает поток и прекращает соединение.
Если же команда "ZipCode", то параметр после команды извлекается и просматривается таблица на предмет наличия города и штата. Город и штат затем передаются клиенту или же передается пустая строка если нет соответствия.
Далее происходит выход из метода. Сервер повторит вызов события снова, как только поступит новая команда, позволяя клиенту посылать множество команд.
Исходный код клиента

unit ClientMain;

interface

uses

Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,

StdCtrls, ExtCtrls, IdAntiFreezeBase,

IdAntiFreeze, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient;

type

TformMain = class (TForm)

Client: TIdTCPClient;

IdAntiFreeze1: TIdAntiFreeze;

Panel1: TPanel;

Panel2: TPanel;

MemoInput: TMemo;

LboxResults: TListBox;

Panel3: TPanel;

Button1: TButton;

Button2: TButton;

Label1: TLabel;

procedure Button2Click(Sender: TObject ) ;

procedure Button1Click(Sender: TObject ) ;

private

public

end ;

FormMain: TformMain;

implementation

{R *.DFM}

procedure TformMain.Button2Click (Sender: TObject ) ;

begin

MemoInput.Clear ;

LboxResults.Clear ;

end ;

procedure TformMain.Button1Click (Sender: TObject ) ;

I: integer ;

S: string ;

begin

ButnLookup.Enabled := true ; try

LboxResults.Clear ;

with Client do begin

Connect; try

LboxResults.Items .Add (ReadLn ) ;

for i:= 0 to memoInput.Lines .Count - 1 do begin

WriteLn ("ZipCode " + memoInput.Lines [ i] ) ;

LboxResults.Items .Add (memoInput.Lines [ i] ) ;

S:= ReadLn ;

if s = "" then begin

S:= "-- No entry found for this zip code." ;

end ;

LboxResults.Items .Add (s) ;

LboxResults.Items .Add ("" ) ;

end ;

WriteLn ("Quit" ) ;

finally Disconnect; end ;

end ;

finally butnLookup.Enabled := true ; end ;

end ;

end .


Единственные части специфические для клиентского компонента - это метод Button1Click.
Компонент Client типа TIdTCPClient и размещен на форме. Изменены следующие свойства: ·Host = 127.0.0.1 - Сервер находится на той же самой машине, что и клиент. ·Port = 6000 - Порт сервера
Метод Button1Click связан с событием OnClick компоненты Button1. При нажатии кнопки вызывается этот метод. Indy часть этого метода может быть уменьшена до следующего: 1.Соединение с сервером (Connect;) 1.Чтения приветствия с сервера. 1.Для каждой строки введенной пользователем в TMemo: 1.Посылка запроса на сервер (WriteLn("ZipCode " + memoInput.Lines[i]);) 1.Чтение ответа с сервера (s:= ReadLn;) 1.Посылка команды Quit (WriteLn("Quit");) 1.Разъединение (Disconnect;)
Тестирование
Данный пример был протестирован и работает при установленном TCP/IP. Вы может изменить его для работы через сеть с одного компьютера с другим. Запустив сервер на другом компьютере и изменив имя или IP сервера на клиенте.
Для тестирования проектов откомпилируйте и запустите сервер. Затем откомпилируйте и запустите клиента. Введите почтовый индекс в мемо поле и нажмите клавишу lookup.
Отладка
Текстовые протоколы очень просто отлаживать, поскольку они могут быть проверены с помощью Телнет. Для этого достаточно знать порт сервера. Zip Code Lookup Server слушает на порту 6000.
Запустите снова Zip Code Lookup Server. Затем откройте консоль (например, окно Dos). Теперь введите:
telnet 127.0.0.1 6000
Теперь вы соединились с сервером. Некоторые серверы при этом посылают приветственное сообщение. Некоторые этого не делают. Вы не увидите вводимых вами строк. Большинство серверов не делают эха, с целью экономии трафика. Тем не менее, вы можете изменить настройки телнет, установкой параметра "Echo On". В разных телнет клиентах это делается по разному, а ряд вообще не имеют такой возможности. Теперь введите:
zipcode 37642
Вы увидите ответ сервера:
CHURCH HILL, TN
Для отсоединения от сервера введите:
quit
Пример 2 - доступ к базе данных
Данный пример эмулирует сервер, который должен выполнять блокирующие задачи, другие чем вызовы сокетов. Многие сервера вынуждены работать в таких условиях. Сервера которые нуждаются в обращение к базе, вызовах внешних процедур или расчетов часто не могут прервать эти вызовы, поскольку это внешних вызовы или из-за сложности этого. Обращение к базе не может быть разбито на маленькие куски и разработчик должен ожидать окончания операции с базой. Это является особенность не только обращений к базе данных, но и другими операциями, таким как сжатие, расчеты и другая обработка того же рода.
Для целей демонстрации, представим, что сервер делает обращение к базе, которое требует 5 секунд для выполнения. Для упрощения выполним это просто с помощью паузы, используем для этого функцию Sleep(5000), вместо реально обращения.
Данный пример также требует меньше детальности, чем предыдущий пример, поскольку многие концепции пока еще не понятны.
Исходный код

unit main;

interface

uses

Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,

IdBaseComponent, IdComponent, IdTCPServer;

type

TformMain = class (TForm)

IdTCPServer1: TIdTCPServer;

procedure IdTCPServer1Execute(AThread: TIdPeerThread) ;

private

public

end ;

FormMain: TformMain;

implementation

{R *.DFM}

procedure TformMain.IdTCPServer1Execute (AThread: TIdPeerThread) ;

I: integer ;

begin

with AThread.Connection do begin

WriteLn ("Hello. DB Server ready." ) ;

I:= StrToIntDef (ReadLn , 0 ) ;

// Sleep is substituted for a long DB or other call

Sleep (5000 ) ;

WriteLn (IntToStr (i * 7 ) ) ;

end ;

end ;

end .

Поскольку событие Execute возникает в контексте потока, код обработки может быть любой длины. Каждый клиент имеет свой собственный поток и не блокирует других клиентов.
Тестирование
Для тестирования DB сервера, откомпилируйте и запустите его. Соединитесь с ним с помощью Телнет на порт 6001. Сервер ответит приветственным сообщением. Введите номер. Сервер "обработает" ваш запрос и ответит через 5 секунд.

Компоненты Indy, применяемые в Delphi 6.

Помимо базовых служб и протоколов Интернет существует широкий набор дополнительных сервисов, возможности которых часто используются Интернет-разработчиками. К тому же далеко не всегда возможность отображения информации с помощью браузера является приемлемым решением для Интернет-приложений. В этом случае разумно использовать Интернет-инфраструктуру для обмена данными, а отображение информации обеспечить за счет более сложных клиентских приложений, разработанных, предположим, на Delphi.

Допустим, требуется реализовать специализированную серверную логику, которая не заложена в стандартные Web-серверы. Для решения такого класса задач в состав Delphi включена библиотека Internet Direct (Indy) компании Nevrona Designs (http://www.nevrona.com/Indy/). Данная библиотека, разработанная специально для Borland Delphi, насчитывает уже восемь версий, последняя из которых вошла в состав новой версии Delphi. Набор компонентов разделен на три группы: клиентские (Indy Client), серверные (Indy Servers) и вспомогательные (Indy Misc).

Indy Clients и Indy Servers

Большинство компонентов Indy Client и Indy Servers представляют собой пары, соответствующие клиентским и серверным частям протоколов и служб (за исключением отдельных, в основном серверных, компонентов типа TunnelMaster и TunnelSlave), и позволяют использовать такие протоколы, как TCP/IP, UDP, NNTP, SMTP, FTP, HTTP, а также службы ECHO, FINGER, WHOIS и т.д.

Клиентские компоненты Indy написаны с использованием сокетов. Сокет со стороны клиента требует соединения с сервером. Если связь установлена, клиент и сервер могут начинать обмен сообщениями. Эти сообщения носят различный характер, но обычно обмен происходит по определенному протоколу (например, НТТР)

TIdTCPClient и TIdTCPServer

Эти компоненты используются для поддержки одного из основных сетевых протоколов - ТСР (Transmission Control Protocol), а также являются базовыми классами для компонентов TIdSMTP и TIdFTP. Класс TIdTCPServer обладает свойством ThreadMgr, по умолчанию равным nil. Если ThreadMgr равно nil, когда TIdTCPServer активизирован, класс TIdThreadMgrDeafault будет создан неявно. В противном случае используется установленный менеджер процессов.

TIdUDPClient и TIdUDPServer

Эти компоненты используются для поддержки сетевого протокола UDP (User Datagram Protocol), а также являются базовыми классами для ряда других компонентов Indy.

TIdChargenServer

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

TIdDayTime и TIdDayTimeServer

Компоненты используются для обеспечения службы времени. Клиент запрашивает, а сервер сообщает текущие дату и время.

TIdDNSResolver

Это клиентский компонент, обслуживающий запросы от сервера DNS (Domain Name Service). Запросы DNS-сервера предназначены для замены имени компьютера на его IP-адрес. TIdDNSResolver является наследником класса TIdUDPClient.

TIdDICTServer

Серверный компонент, поддерживающий протокол Dictionary Server Protocol (DICT) - серверный словарь на базе TCP-протокола, который позволяет клиенту получать доступ к словарю естественного языка.

TIdDISCARDServer

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

TI dEcho и TI dECHOServer

Компоненты предназначены для обеспечения службы отклика, используемой, как правило, для проверки работоспособности сети. Клиент посылает текстовое сообщение серверу, сервер возвращает сообщение клиенту. Если сообщение искажено, сеть работает с ошибками.

TIdFinger и TIdFingerServer

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

TIdFTP

Компонент включает полную поддержку протокола передачи файлов - FTP (File Transfer Protocol). Поддерживается пассивная и активная передача данных, а также такие операции, как GET и PUT, удаление директорий, получение квот, размеров файлов и каталогов. В своей работе TI dFTP использует класс TIdSimpleServer. Когда выполняется передача файла по протоколу FTP, вторичное соединение по протоколу TCP открыто для передачи данных и закрывается, когда данные были переданы. Такое соединение называется «канал передачи данных», уникальный для каждого передаваемого файла.

TIdGopher и TIdGopherServer

Эти компоненты предназначены для обеспечения сетевого протокола, вытесненного в последнее время из WWW (World Wide Web) протоколом HTTP. Сервер, реализующий этот протокол, обеспечивает иерархическую распределенную систему поддержки документооборота. Пример использования этой пары компонентов, находящийся в директории \demos\indy\GopherClient и \demos\indy \GopherServer, демонстрирует, как при помощи этого протокола можно предоставлять в локальной сети информацию о файлах, находящихся на вашем компьютере, в том числе и о закрытых.

TIdHostNameServer

Серверный компонент, предназначенный для передачи клиентам локального имени сервера.

TIdHTTP и TIdHTTPServer

Компоненты используются для обеспечения сетевого протокола HTTP (поддерживаются версии 1.0 и 1.1, включая операции GET, POST и HEAD). Кроме того, обеспечивается поддержка аутентификации и применения proxy-серверов. Серверный компонент используется для предоставления услуг другому Web-серверу, поддерживающему данный протокол. TIdHTTPServer облегчает реализацию таких функций, как cookies, управление состояниями и др.

TIdIcmpClient

Клиентский компонент, предназначенный для обеспечения протокола ICMP (Internet Control Message Protocol), с помощью которого осуществляется выполнение операции ping и трассировка сети.

TIdPOP3

Клиентский компонент, предназначенный для обеспечения протокола POP (Post Office Protocol), включая поддержку MIME-кодирования и декодирования, а также передачу многобайтных символов.

TIdIMAP4Server

Серверный компонент, предназначенный для поддержки операций по протоколу IMAP (Internet Message Access Protocol) на сервере. Протокол позволяет производить поиск сообщений электронной почты на сервере. Различие протоколов IMAP и РОР заключается в том, что протоколу РОР требуется дополнительная память для хранения данных, а протокол IMAP обращается к серверу вместо клиентской машины. IMAP4 создавался для замены POP3, однако до сих пор протокол POP3 остается широко используемым стандартом.

TIdIRCServer

Серверный компонент, предназначенный для поддержки наиболее часто используемых в Интернете сервисных операций, обычно называемых chat (для дружеских бесед). Компонент обеспечивает базовые конструктивные блоки для IRC (Internet Relay Chat) сервера.

TIdMappedPortTCP

Серверный компонент, предназначенный для создания отображаемых портов, которые часто используются в proxy-серверах. Методы этого компонента позволяют отобразить один порт на другой. Например, порт 80 может быть отображен к порту 3000, и все запросы к первому порту (порт 80) будут переадресованы на второй порт (порт 3000).

TIdNNTP и TIdNNTPServer

Эти компоненты необходимы для обеспечения сетевого протокола NNTP (Network News Transfer Protocol), используемого в службах новостей. Клиентский компонент включает поддержку MIME-кодирования и декодирования, а также поддержку многобайтных символов и альтернативных кодировок. Серверный компонент позволяет создавать серверы новостей. Важно отметить, что TIdNNTPServer является не полнофункциональным сервером новостей, а компонентом, обеспечивающим базовые возможности для такого сервера.

TIdQOTD и TIdQOTDServer

Компоненты используются для обеспечения службы «цитат дня» (Quote of the Day). С помощью клиентского компонента осуществляется соединение с экземпляром серверного компонента для получения ежедневной цитаты. Каждый экземпляр сервера содержит уникальную базу данных цитат.

TIdSMTP

Клиентский компонент, предназначенный для применения в приложениях протокола SMTP (Simple Mail Transfer Protocol), обеспечения поддержки аутентификации, MIME-кодирования и декодирования, а также для поддержки многобайтных символов.

TIdSNTP

Клиентский компонент, предназначенный для обеспечения протокола SNTP (Simple Network Time Protocol) - службы времени. Может использоваться для соединения с любой службой времени с целью определения текущих даты и времени.

TIdSimpleServer

Серверный компонент, обеспечивающий облегченный ТСР-сервер. Позволяет организовывать соединение «точка-точка». Используется для создания серверов с единственным пользователем, то есть может единовременно обслуживать только одно подключение. В отличие от компонента TIdTCPServer не порождает вторичные процессы при ожидании запросов от клиентов и при обработке этих запросов. Другими словами, если сервер обслуживает запрос от какого-то клиента, а в это время к нему обращается для подключения другой клиент, то он будет блокирован до конца обработки первого запроса.

TIdTelnet и TIdTelnetServer

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

TIdTime и TIdTimeServer

Клиентский компонент является альтернативой компонента TIdSNTP для определения времени. Важно отметить, что форматы этих двух протоколов различны. TIdTime основан на формате RFC 868 (возвращает время во внутреннем стандарте ОС UNIX, выполняя все необходимые преобразования). Серверный компонент подобен по функционированию DayTime-серверу. Может использоваться для реализации службы времени на локальном компьютере. Дополнительного кода не требуется, достаточно создать экземпляр TIdTimeServer, который будет возвращать время внутренних часов серверного компьютера.

TIdTrivialFTP и TIdTrivialFTPServer

Эти компоненты необходимы для организации простейшего протокола передачи файлов. Клиентский компонент этого протокола используется для соединения с экземпляром соответствующего серверного компонента. Протокол предназначен для частных, облегченных, локальных случаев передачи файлов, например в локальных вычислительных сетях или для загрузки (выгрузки) таблиц маршрутизации в маршрутизаторы. Ввиду ослабленных характеристик этого протокола его использование не рекомендуется в случае применения алгоритмов аутентификации или любых других механизмов защиты. Основное назначение данного протокола - передача файлов аппаратному устройству с целью его модификации.

TIdTunnelMaster и TIdTunnelSlave

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

TIdWhois и TIdWhoIsServer

Этот клиентский компонент осуществляет соединение с любым стандартным Whois-сервером, позволяющим получить информацию о доменах. Серверный компонент обеспечивает базовую функциональность NIC сервера.

Indy Misc

Страница палитры компонентов Indy Misc (Indy Miscellaneous Components) включает кодеки BASE64, UUE, Quoted Printable и другие распространенные форматы обмена данными через e-mail, кодеры (MD2, MD4 и MD5) для стандартов криптографии, используемые для хранения паролей и электронных подписей в необратимом (трудно поддающемся дешифрованию) виде, а также многие другие полезные компоненты и утилиты, часто применяемые при разработке Интернет-приложений.

TIdAntiFreeze

Вследствие блочной организации алгоритмов компонентов Indy зачастую создается впечатление, что приложение «зависло», в то время как соединение работает. Чтобы исключить использование вторичных процессов (threads) при организации коммуникаций для предотвращения замораживания (freeze) приложения, достаточно поместить на форму указанный компонент.

Компонент работает, анализируя запросы из стека протокола TCP/IP и посылая сообщения приложению во время задержки при возникновении блокировки внешних соединений, что создает иллюзию работающего кода. Поскольку воздействие компонента осуществляется на блокированные соединения только для главного процесса, использование TIdAntiFreeze во вторичных процессах приложения не требуется. Необходимо помнить, что компонент TIdAntiFreeze замедляет работу соединений, поскольку работа главного процесса периодически прерывается для обработки сообщений. Отсюда следует, что надо заботиться о том, чтобы разрабатываемое приложение не тратило слишком много времени на обработку сообщений, включая OnClick, OnPaint, OnResize и др. В какой-то степени этим можно управлять через свойства класса TIdAntiFreeze. Использование данного компонента не является обязательным, но позволяет решить проблему синхронизации соединений с визуальным интерфейсом приложения.

TIdDateTimeStamp

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

TIdIPWatch

Это компонент, основанный на таймере, который постоянно контролирует изменения в IP-адресе компьютера. События компонента возникают, когда выявлено изменение. Указанный компонент обычно используют для обнаружения факта появления связи компьютера с Интернетом или любой другой сетью. Изменение в IP-адресе в этой ситуации может произойти из-за назначения IP-адреса DHCP-сервером (Dynamic Host Configuration Protocol) при соединении с новой сетью.

TIdLogDebug

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

TIdMessage

Компонент используется в комбинации с другими компонентами, чтобы должным образом расшифровать или кодировать сообщения. Это могут быть POP-, SMTP- и NNTP-компоненты. Класс поддерживает MIME-шифрование и расшифровку, многобайтные символы и кодировку ISO.

TIdNetworkCalculator

Один из немногих компонентов Indy, который можно использовать при конструировании приложений. Сетевой калькулятор может служить для вычислений, производимых над IP-адресами, включая сетевые маски, подсеть, классы сети и т.д.

TIdThreadMgrDefault

Компонент обеспечивает управление вторичными процессами по умолчанию. Создается в случае, если для какого-либо компонента Indy, поддерживающего управление процессами, не определен экземпляр класса TIdThreadManager. Компонент обеспечивает только основные возможности управления вторичными процессами: создает и уничтожает их по требованию.

TIdThreadMgrPool

Более продвинутый компонент управления процессами, чем TIdThreadMgrDefault, потому что он объединяет процессы, а не создает или уничтожает их по требованию.

TIdVCard

VСard - электронный эквивалент визитной карточки, может содержать персональную информацию владельца, графические данные.

TIdIMFDecoder

Предназначен для декодирования Интернет-сообщений. Является наследником класса TIdCoder, так же как и все остальные компоненты-кодировщики. Класс TIdCoder осуществляет декодирование в соответствии со стандартом формата текстовых Интернет-сообщений ARPA RFS-822, предложенным в августе 1982 года, и стандартом для обмена USENET-сообщениями RFC 1036, предложенным в декабре 1987 года.

Компонент расширяет возможности класса TIdCoder, позволяя обнаруживать формат RFS-822 по контексту заголовков, обеспечивая режим расшифровки при приеме и MIME-шифрование и расшифровку. Компонент TIdIMFDecoder используется в классе TIdMessageClient для декодирования получаемых и передаваемых сообщений.

TIdQuotedPrintableEncoder

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

TIdBase64Encoder

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

TIdUUEncoder

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

TIdXXEncoder

Этот метод шифрования едва ли когда-либо будет использоваться. По сути, это то же самое UU-кодирование, но с другой таблицей шифрования.

TIdCoderMD2

Компоненты с различными разновидностями алгоритма шифрования MD (Message Digest). Все они основаны на перемешивании, являются односторонними и не имеют алгоритмов расшифровывания.

Компоненты протокольных клиентов и серверов могут быть использованы для разработки серверных и клиентских Интернет-приложений, совместно или взамен базовых (ClientSocket, ServerSocket) и других компонентов из состава палитры Internet и Fastnet. Компоненты Indy не используют архитектуру WebBroker, реализуя поддержку Интернет-протоколов и служб на нижнем уровне непосредственно в своем исходном коде (исходные коды прилагаются).

TIdConnectionInterceptOpenSSL и TIdServerInterceptOpenSSL

Протокол SSL - Secure Sockets Layer (Секретный Уровень Сокетов), обеспечивающий секретность и надежность связи между двумя приложениями, имеет два уровня. На низком уровне многоуровневого транспортного протокола (например, TCP) SSL является протоколом записи и используется для инкапсуляции различных протоколов более высокого уровня. Преимущество SSL состоит в том, что он является независимым протоколом прикладной программы, при этом протокол более высокого уровня может быть использован поверх SSL.

SSL осуществляет защиту связи, которая имеет три основные функции: обеспечение конфиденциального соединения; шифрование с открытым ключом (используется для подтверждения подлинности адресата); поддержка надежности передачи данных.

  • Симметричная криптография используется для шифрования данных (например, DES, RC4 и т.д.).
  • Цифровая подпись обеспечивается при помощи асимметричного шифрования с открытым ключом (например, RSA, DSS и т.п.).
  • Надежность связи, транспортировка сообщения включает проверку целостности сообщения посредством корректирующих кодов MAC, безопасных хеш-функций (например, SHA, MD5, и т.д.) с использованием MAC-вычислений.

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

Компоненты TIdConnectionInterceptOpenSSL и TIdServerInterceptOpenSSL обеспечивают соединение как со стороны клиента, так и со стороны сервера в соответствии с протоколом SSL. Необходимо отметить, что компоненты TIdConnectionInterceptOpenSSL и TIdServerInterceptOpenSSL есть только в Delphi 6, а в Kylix отсутствуют. Это связано со сложностью протокола, который в случае реализации Windows основан на функциях операционной системы.

Примеры использования компонентов Indy можно найти в каталогах /Delphi6/Demos/Indy. Всего библиотека Indy в версии 8.0 содержит 69 компонентов. Заявлено, что в версии 9.0 указанная библиотека будет содержать 86 компонентов. Все компоненты унифицированы и включены как в Delphi 6, так и в Kylix, что позволяет использовать их для разработки кросс-платформенных приложений. Все компоненты Indy поддерживают многопоточность.

В компонентах Indy реализована почти вся функциональность, имеющаяся в компонентах Internet и Fastnet, что наглядно показано в таблице.

Компоненты Fastn et Компоненты Indy Назначение компонентов
1 TserverSocket, TClientSocket TIdTCPserverSocket, TIdTCPClientSocket Взаимодействие двух компьютеров (клиента и сервера) с помощью протокола TCP/IP
2 TNMDayTime TIdDayTime, TIdDayTimeServer Запрос сервера о текущем времени
3 TNMEcho TIdEcho, TIdEchoServer Используются для связи с сервером отклика
4 TNMFinger TIdFinger, TIdFingerServer Используются для получения информации о пользователе с поискового Интернет-сервера
5 TNMFTP TIdFTP, TIdTrivialFTP, TIdTrivialFTPServer Обеспечивают передачу файлов с помощью протокола FTP
6 TNMHTTP TIdHTTP, TIdHTTPServer Используют протокол HTTP для обмена данными
7 TNMMsgServ, TNMMsg Используются для передачи простых текстовых сообщений от клиента к серверу
8 TNMNNTP TIdNNTP, TIdNNTPServer Поддерживают обмен данными с сервером новостей
9 TNMPOP3 TIdPOP3 Используются для получения электронной почты с почтового сервера с помощью протокола POP3
10 TNMSMTP TIdSMTP Используются для отправки электронной почты через почтовый сервер Интернет
11 TNMStrm, TNMStrmServ Передают двоичные данные, записанные в поток, с помощью протокола TCP/IP
12 TNMUDP TIdUDP, TIdUDPServer Осуществляют пересылку данных с использованием протокола UDP
13 TpowerSock, TNMGeneralServer Инкапсулированные в виде компонентов классы, которые являются базовыми для написания собственных клиентов (Powersock) и серверов (NMGeneralServer)
14 TNMUUProcessor TIdUUEncoder, TIdUUDecoder Осуществляют перекодировку двоичных файлов в формат MIME или UUENCODE
15 TNMURL Перекодирует строки в формат HTML и осуществляет обратную перекодировку

Исключение составляют такие классы, как TNMMsgServ, TNMMsg, TNMStrm, TNMStrmServ, TpowerSock, TNMGeneralServer, TNMURL, которые либо реализуют морально устаревшие протоколы, либо обладают функциональностью, реализованной в большой группе альтернативных классов.

Однако в отличие от своих предшественников - компонентов Internet и Fastnet, в Indy богаче представлены серверные компоненты и компоненты перекодирования и шифрования данных, а также поддержка аутентификации (палитра Indy Misc). Как видно из приведенной выше таблицы, основные протоколы и службы обеспечиваются не только клиентскими, но и серверными компонентами. Это службы времени, отклика, получения информации о пользователе, а также протоколы HTTP, NNTP, UDP и даже простейший вариант FTP.

Некоторые примеры применения компонентов Indy

В компонентах Indy, которые содержатся в Delphi, IP-адрес определяется в свойстве Host, как правило, только в клиентских приложениях. Компоненты, размещаемые на сервере, имеют методы, позволяющие начать или прекратить опрос соответствующего порта, - например изменение свойства Active компонента IdTCPServer начинает или прекращает опрос соответствующего порта. После установки связи между клиентом и сервером можно начинать передачу данных.

В компонентах Indy большое внимание уделяется безопасности и надежности при работе с данными. Например, в компоненте IdTCPClient есть методы Connect и Disconnect. Применяя технику программирования, как в приведенном ниже коде со стороны клиента:

with TCPClient do begin Connect; try lstMain.Items.Add(ReadLn); finally Disconnect; end; end;

и используя свойство Connection, передаваемое в качестве параметра экземпляра AThread класса TIdPeerThread, со стороны сервера:

with AThread.Connection do begin WriteLn("Hello from Basic Indy Server server."); Disconnect; end;

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

Обратите внимание на методы ReadLn и WriteLn соответствующих классов - они напоминают стандартные операторы ввода-вывода Pascal. Это дань технике программирования в UNIX, где большинство системных операций выполняются благодаря чтению и записи в соответствующие файлы.

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

procedure TForm1.IdECHOServer1Connect(AThread: TIdPeerThread); begin lblStatus.caption:= "[ Serving client ]"; end;

В Indy представлены компоненты, реализующие протоколы с клиентскими и серверными частями, присущие только этой библиотеке. Компоненты TIdGopherServer и TIdGopher, благодаря методам GetExtendedMenu, GetFile, GetMenu, GetTextFile на клиентской стороне и ReturnGopherItem, SendDirectoryEntry - на стороне сервера, помогают осуществить просмотр файлов различного типа, в том числе помеченных как скрытые, а также директорий на удаленном компьютере (подобно тому, как это делает команда dir *.* в операционной системе MS-DOS).

При помощи компонентов IdSMTP и IdMessage можно легко создать свое Web-приложение, способное отправлять почту по протоколу SMTP.

При этом класс IdMessage (один из 23 компонентов со страницы Indy Misc) отвечает за формирование сообщения, что вытекает из его названия, а IdSMTP - за организацию соединения с почтовым сервером.

Технология, применяемая в Indy, использует операции чтения и записи с блокировкой. Любая операция Connect, используемая в Indy, ожидает завершения соединения. При работе с клиентскими компонентами Indy, как правило, требуется выполнение следующих операций:

  • запросить соединение с сервером;
  • осуществить запросы к серверу на чтение и запись (в зависимости от типа сервера шаг выполняется единожды или повторяется много раз);
  • закончить соединение с сервером и разъединиться.

Компоненты Indy разрабатывались так, чтобы обеспечить сверхвысокий уровень абстракции. Запутанность и подробности стека TCP/IP скрыты от программиста, с тем чтобы он мог сосредоточиться на текущих задачах.

Следующий небольшой пример показывает типичную сессию клиентского компонента:

with IndyClient do begin Host:= "zip.pbe.com"; // Host to call Port:= 6000; // Port to call the server on Connect; try // Your code goes here finally Disconnect; end; end;

В примере, даже если соединение с сервером не будет установлено, связь корректно разорвется благодаря использованию оператора try-finally.

Серверные компоненты Indy описывают разнообразные модели серверов, которые можно использовать в зависимости от потребностей и применяемого протокола.

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

Иными словами, для каждого клиентского подключения класс TIdTCPServer использует уникальный вторичный поток, вызывая обработчик события OnExecute этого потока. Формальным параметром метода OnExecute является ссылка на экземпляр класса Athread, соответствующего созданному потоку. Свойство Connection этого класса - ссылка на класс TIdTCPConnection, экземпляр которого создается для обработки клиентского запроса. TIdTCPConnection поддерживает чтение и запись через соединение, а также установление и завершение сеанса связи.

Протокол UDP работает без предварительной установки соединения с сервером (каждый посланный пакет является самостоятельным набором данных, а не частью большой сессии или соединения). В то время как TIdTCPServer порождает отдельные потоки для каждого соединения, TIdUDPServer использует или главный поток, или единственный вторичный поток, который обрабатывает все запросы протокола UDP. Когда TIdUDPServer активен, создается поток для прослушивания входящих UDP-пакетов. Для каждого полученного пакета возникает событие OnUDPRead или в основном потоке, или в контексте прослушивающего потока - в зависимости от значения свойства ThreadedEvent. Когда ThreadedEvent принимает значение False, событие возникает в основном потоке, в противном случае - в прослушивающем потоке. Пока происходит обработка события, другие операции сервера блокируются. Поэтому важно следить, чтобы процедуры OnUDPRead выполнялись как можно быстрее.

Если нужно создать клиентское приложение нового клиента для существующего сервера с использованием существующего протокола, ваша задача состоит исключительно в разработке и отладке клиентского приложения. Однако, когда приходится разрабатывать и клиентское, и серверное приложения с применением существующего или нового протокола, мы сталкиваемся с классической проблемой «яйца и курицы». С чего начинать программирование - с клиента или с сервера?

Очевидно, в итоге должны быть созданы и клиент, и сервер. Для многих приложений, особенно использующих текстовый протокол (например, HTTP), проще начать создание приложения с проектирования сервера. А для его отладки имеется удобный клиент, который уже существует. Это - консольное приложение Telnet, которое имеется и на Windows, и на UNIX.

Если набрать консольную команду telnet 127.0.0.1 80 с IP-адресом локального компьютера и номером порта 80, используемым по умолчанию Web-серверами, то приложение откликнется текстом, представленным на рис. 6, в случае ОС Windows 2000 и IIS 5.0.

Для создания самого простого сервера с использованием компонентов Indy необходимо:

Если необходимо спроектировать сервер, который будет не только корректно информировать своих клиентов о разрыве соединения, но и выдавать для них информацию о возникших ошибочных ситуациях, применяйте оператор try-except вместо try-finally - например, как показано в следующем примере:

procedure TDataModule1.IdTCPServer1Execute(AThread: IdPeerThread); var s: String; begin with AThread.Connection do try try s:= ReadLn; // Perform the task of the server here // if no exception is raised, // write out the server"s response WriteLn(s); except on e: Exception do begin WriteLn(e.Message); end; //on end; //try except finally Disconnect; end; end;

Этот небольшой пример демонстрирует этапы создания простого текстового сервера, а также способы его отладки.

Вышеописанный сервер является типичным примером организации современного распределенного вычисления.

Особенности создания многозвенных приложений

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

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

Итак, мы приступаем к разработке приложения с трехзвенной архитектурой. Для создания сервера базы данных с использованием компонентов Indy необходимо:

  1. Создать новый проект.
  2. Поместить на главную форму проекта экземпляр компонента TIdTCPServer с палитры Indy Servers.
  3. Присвоить свойству DefaultPort экземпляра класса TIdTCPServer1 значение 6001 (рекомендуется присваивать большие значения, чтобы избежать дублирования номеров портов у различных приложений), а свойству Active - значение true.
  4. Добавить в проект новый модуль, выбрав команду File | New | Data Module, и поместить на него экземпляры компонентов SQLConnection и SQLDataSet с закладки dbExpress на палитре компонентов.
  5. Установить свойство ConnectionName класса SQLConnection в IBLocal и LoginPrompt в False. Если вы не конфигурировали IBLocal на базу данных employee.gdb, сначала проделайте эту процедуру.
  6. Установить свойство SQLConnection класса SQLDataSet в SQLConnection1 и присвоить свойству CommandText оператор SQL: select CUSTOMER, CONTACT_FIRST, CONTACT_LAST from CUSTOMER where CUST_NO = :cust.

Всем привет!

При разработки очередного Web-проекта встала задача – реализовать клиентское ПО на Delphi, которое бы передавало данные на сервер, используя метод POST. Приложение должно передавать текст и загружать файлы на Web-сервер.

Реализация такой отправки данных с использованием серверных языков Web разработки (например, PHP) довольно проста, а вот если необходимо написать прикладное, многопользовательское ПО взаимодействующее с сервером, то тут уже чуточку сложнее. Способ прямого подключения к БД и по FTP к серверу из Delphi – отпадает т.к. это не безопасно, не надежно (смена паролей, данных подключения и т.д.) и создает доп. проблемы с совместимостью ПО на стороне клиента. Для решения задачи я решил написать на языке PHP скрипты (серверную часть), которые будут обрабатывать входящие POST запросы и выдавать результат обратно клиенту (приложение на Delphi). Преимущества такого подхода в том, что все подключения и обработки данных происходят на сервере, что намного безопаснее прямого «коннекта».

Начав «гуглить» было выдано множество разрозненной информации, в основном это были форумы, но все это было кусками. Одно точно определил, что использоваться будет Indy, а именно компонент IdHTTP с реализованным методом POST. По сути все просто, данный метод принимает два параметра Url ресурса и DataStream(поток данных), в ответ же отдает результат в текстовом виде(так же это может быть HTML-код страницы). Основное заключалось в правильном формировании DataStream(потока передаваемых данных), но по ходу вылезли еще дополнительные подводные камни, а именно русская кодировка (будь она не ладна). Вот тут-то и началось веселье на несколько часов блуждания на просторах сети. В общем, хватит болтовни, давайте перейдем к практике и реализации софта.

Итак, программа проста. Она должна отправить на сервер данные методом POST, данные содержат «Заголовок » (строка), «Описание » (многострочный текст) и графический файл (jpg,png,gif-бинарные данные). Сервер должен принять эти данные, обработать, сохранить графический файл на сервере и вернуть ответ. В качестве ответа вернем Delphi приложению, тот же текст только с добавлением меток и ссылку на загруженный файл. Больше ничего.

Начнем с реализации серверной части (подобие API сайта). Откройте любой текстовый редактор (блокнот) и в нем пропишите следующий код:

"; } else { echo "Заголовок: Отсутствует"."
"; } //Проверяем в поступивших данных наличие данных поля "content" if (!empty($_POST["content"])){ echo "Содержимое: ".$_POST["content"]."
"; } else { echo "Содержимое: Отсутствует"."
"; } //Проверяем в поступивших данных наличие прикрепленного файла "file" if (!empty($_FILES["file"])) { $finfo = pathinfo($_FILES["file"]["name"]); //получаем инфо о файле (имя, расширение и т.д.) //Проверяем тип файла в списке допустимых типов(ИМПРОВИЗАЦИЯ:)) if (stripos("jpgpnggif",$finfo["extension"])==0){ echo ">>>>>>>Недопустимый тип файла<<<<<<<<"; exit; //Если не допустим тип, полностью останавливаем скрипт } $fname = "files/" . "testimgfile." . $finfo["extension"]; //формируем путь и новое имя файла move_uploaded_file($_FILES["file"]["tmp_name"],$fname);//сохраняем временный файл "tmp_name" в файл $fname echo "http://".$_SERVER["HTTP_HOST"]."/".$fname; //возвращаем полный путь к файлу } ?>

Обратите внимание ! При сохранении (через блокнот) необходимо указать кодировку «UTF-8», иначе будут проблемы с отображением кириллицы!

Скрипт постарался снабдить подробными комментариями. Скопируйте этот скрипт на свой Web-сервер, если такового нет, для теста можете воспользоваться моим скриптом, расположен он по адресу: http://api..php

В макете используются следующие компоненты: Label, Button(2шт.), Edit(2шт.), Memo(2шт.), CheckBox, OpenDialog, IdHTTP. Задайте следующим компонентам имена (свойство “Name ”):

  1. Edit(заголовок) – Name= title;
  2. Edit(путь к файлу) Name = imgfile;
  3. Memo(Содержание) Name = content;
  4. Memo(Результат) – Name = response;
  5. Button(…) – Name = chkfile ;
  6. Button(POST) – Name = PostBut ;
  7. OpenDialog(Диалог выбора файла) – Name = PictDialog ;

IdHTTP1 и CheckBox1 оставим не меняя (надоело! :)))).

Чтобы случайно не «подредактировать » путь в Edit(imgfile ), выставим ему свойство ReadOnly в True. Так же, у imgfile и chkfile свойство Enabled выставьте в false. Активировать их будем с помощью CheckBox т.е. предоставим возможность выбора – загружать изображение или нет.

Для OpenDialog(PictDialog ) необходимо задать фильтр (свойство Filter) следующим образом:

Собственно визуальная подготовка окончена! Приступаем к кодированию!

В проекте мы будем формировать поток данных с помощью типа идущего в комплекте с Indy – TidMultiPartFormDataStream. Хотя и попадались варианты реализации на TStream, но работать с TidMultiPartFormDataStream – проще!

Чтобы этот тип стал доступен нашему проекту, необходимо в Uses добавить следующую библиотеку: IdMultipartFormData .

Для CheckBox1 создайте событие OnClick (двойным нажатием мыши по объекту) и пропишите в это событие следующий код:

Procedure TForm1.CheckBox1Click(Sender: TObject); begin //делаем активными или неактивными элемнты пути файла и кнопки диалога imgfile.Enabled:=CheckBox1.Checked; chkfile.Enabled:=CheckBox1.Checked; end;

Здесь мы активируем объекты imgfile и chkfile в зависимости от наличия галочки (если галочка стоит, то объекты становятся активными).

Теперь организуем выбор изображения. Для этого создайте событие OnClick на кнопке chkfile (так же двойным кликом по объекту) и пропишите следующее:

Procedure TForm1.chkfileClick(Sender: TObject); begin //открываем диалог и вносим полный путь к файлу в imgfile(TEdit) if PictDialog.Execute then imgfile.Text:= PictDialog.FileName; end;

Это событие вызовет диалог выбора изображения и если пользователь нажмет «Открыть », то путь на этот файл будет добавлен в imgfile .

И вот мы подошли к финальной кнопке “POST”. Создайте событие OnClick для данной кнопки и добавьте следующий код:

Procedure TForm1.PostButClick(Sender: TObject); var dataPost:TIdMultiPartFormDataStream; begin dataPost:=TIdMultiPartFormDataStream.Create; dataPost.AddFormField("title",title.Text,"utf-8").ContentTransfer:= "8bit"; dataPost.AddFormField("content",content.Text,"utf-8").ContentTransfer:= "8bit"; if CheckBox1.Checked and (trim(imgfile.Text)="") then //проверка выбран файл или нет begin ShowMessage("Необходимо выбрать графический файл!"); exit; end; if CheckBox1.Checked then dataPost.AddFile("file",imgfile.Text,""); //добавляем поле с файлом response.Text:= StringReplace(idHTTP1.Post("http://api..php",dataPost),"
",#13#10,); datapost.Free; end;

Итак, по порядку (хотя и есть комментарии):

Datapost – объект типа TIdMultiPartFormDataStream . Позволяет формировать структуру POST запроса состоящую из полей разного типа.

dataPost . AddFormField (" title ", title . Text ," utf -8 "). ContentTransfer := " 8 bit "; – добавляет в DataPost поле с именем «title», значение из «title.Text», устанавливает кодировку передаваемых данных «utf-8»(параметр не обязательный, но без его явного указания кириллица передается знаками вопроса «?») и очень важный метод «ContentTransfer». Без этого метода на сервер улетают данные «абракадаброй ». Обратите внимание, имя поля(«title») на передающей стороне, должно соответствовать имени прописанному в скрипте: $_POST["title"].

Аналогично передаются данные в поле «content».

dataPost . AddFile (" file ", imgfile . Text ,"") – этой строкой мы формируем поток с данными из файла.

Все, данные сформированы, осталось их передать скрипту на сервере и получить ответ:

response.Text:= StringReplace(idHTTP1.Post("http://api..php",dataPost),"
",#13#10,);

т.к. TMemo не понимает тэг переноса строки «
», мы воспользуемся функцией « » для его замены на понятные символы переноса строки «#13#10».

По завершению всего очищаем память от объекта DataPost строкой:

datapost.Free;

Хотя в нашем примере это произойдет автоматически по окончании процедуры, но все ж…

Собственно результат работы программы на экране:

Таким образом, мы можем отправить на сервер сколь угодно данных, файлов, обработать эти данные на сервере и сообщить приложению ответом, результат выполнения скрипта. Это может быть даже просто 0 или 1, что станет сигналом к дальнейшей реакции приложения.

Все. Всем удачи. Надеюсь, информация была полезной, и Вы найдете ей применение.

Готовый пример и скрипт Вы можете скачать .

Полный код модуля:

Unit PostUnit; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdHTTP, IdMultipartFormData, Vcl.ExtDlgs; type TForm1 = class(TForm) IdHTTP1: TIdHTTP; title: TEdit; content: TMemo; PostBut: TButton; response: TMemo; Label1: TLabel; Label2: TLabel; Label3: TLabel; imgfile: TEdit; chkfile: TButton; Label4: TLabel; CheckBox1: TCheckBox; PictDialog: TOpenDialog; procedure PostButClick(Sender: TObject); procedure chkfileClick(Sender: TObject); procedure CheckBox1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.CheckBox1Click(Sender: TObject); begin //делаем активными или неактивными элемнты пути файла и кнопки диалога imgfile.Enabled:=CheckBox1.Checked; chkfile.Enabled:=CheckBox1.Checked; end; procedure TForm1.chkfileClick(Sender: TObject); begin //открываем диалог и вносим полный путь к файлу в imgfile(TEdit) if PictDialog.Execute then imgfile.Text:= PictDialog.FileName; end; procedure TForm1.PostButClick(Sender: TObject); var dataPost:TIdMultiPartFormDataStream; begin dataPost:=TIdMultiPartFormDataStream.Create; dataPost.AddFormField("title",title.Text,"utf-8").ContentTransfer:= "8bit"; dataPost.AddFormField("content",content.Text,"utf-8").ContentTransfer:= "8bit"; if CheckBox1.Checked and (trim(imgfile.Text)="") then //проверка выбран файл или нет begin ShowMessage("Необходимо выбрать графический файл!"); exit; end; if CheckBox1.Checked then dataPost.AddFile("file",imgfile.Text,""); //добавляем поле с файлом response.Text:= StringReplace(idHTTP1.Post("http://api..php",dataPost),"
",#13#10,); datapost.Free; end; end.

Компоненты Indy, применяемые в Delphi 6.

Помимо базовых служб и протоколов Интернет существует широкий набор дополнительных сервисов, возможности которых часто используются Интернет-разработчиками. К тому же далеко не всегда возможность отображения информации с помощью браузера является приемлемым решением для Интернет-приложений. В этом случае разумно использовать Интернет-инфраструктуру для обмена данными, а отображение информации обеспечить за счет более сложных клиентских приложений, разработанных, предположим, на Delphi.

Допустим, требуется реализовать специализированную серверную логику, которая не заложена в стандартные Web-серверы. Для решения такого класса задач в состав Delphi включена библиотека Internet Direct (Indy) компании Nevrona Designs (http://www.nevrona.com/Indy/). Данная библиотека, разработанная специально для Borland Delphi, насчитывает уже восемь версий, последняя из которых вошла в состав новой версии Delphi. Набор компонентов разделен на три группы: клиентские (Indy Client), серверные (Indy Servers) и вспомогательные (Indy Misc).

Indy Clients и Indy Servers

Большинство компонентов Indy Client и Indy Servers представляют собой пары, соответствующие клиентским и серверным частям протоколов и служб (за исключением отдельных, в основном серверных, компонентов типа TunnelMaster и TunnelSlave), и позволяют использовать такие протоколы, как TCP/IP, UDP, NNTP, SMTP, FTP, HTTP, а также службы ECHO, FINGER, WHOIS и т.д.

Клиентские компоненты Indy написаны с использованием сокетов. Сокет со стороны клиента требует соединения с сервером. Если связь установлена, клиент и сервер могут начинать обмен сообщениями. Эти сообщения носят различный характер, но обычно обмен происходит по определенному протоколу (например, НТТР)

TIdTCPClient и TIdTCPServer

Эти компоненты используются для поддержки одного из основных сетевых протоколов - ТСР (Transmission Control Protocol), а также являются базовыми классами для компонентов TIdSMTP и TIdFTP. Класс TIdTCPServer обладает свойством ThreadMgr, по умолчанию равным nil. Если ThreadMgr равно nil, когда TIdTCPServer активизирован, класс TIdThreadMgrDeafault будет создан неявно. В противном случае используется установленный менеджер процессов.

TIdUDPClient и TIdUDPServer

Эти компоненты используются для поддержки сетевого протокола UDP (User Datagram Protocol), а также являются базовыми классами для ряда других компонентов Indy.

TIdChargenServer

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

TIdDayTime и TIdDayTimeServer

Компоненты используются для обеспечения службы времени. Клиент запрашивает, а сервер сообщает текущие дату и время.

TIdDNSResolver

Это клиентский компонент, обслуживающий запросы от сервера DNS (Domain Name Service). Запросы DNS-сервера предназначены для замены имени компьютера на его IP-адрес. TIdDNSResolver является наследником класса TIdUDPClient.

TIdDICTServer

Серверный компонент, поддерживающий протокол Dictionary Server Protocol (DICT) - серверный словарь на базе TCP-протокола, который позволяет клиенту получать доступ к словарю естественного языка.

TIdDISCARDServer

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

TI dEcho и TI dECHOServer

Компоненты предназначены для обеспечения службы отклика, используемой, как правило, для проверки работоспособности сети. Клиент посылает текстовое сообщение серверу, сервер возвращает сообщение клиенту. Если сообщение искажено, сеть работает с ошибками.

TIdFinger и TIdFingerServer

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

Компонент включает полную поддержку протокола передачи файлов - FTP (File Transfer Protocol). Поддерживается пассивная и активная передача данных, а также такие операции, как GET и PUT, удаление директорий, получение квот, размеров файлов и каталогов. В своей работе TI dFTP использует класс TIdSimpleServer. Когда выполняется передача файла по протоколу FTP, вторичное соединение по протоколу TCP открыто для передачи данных и закрывается, когда данные были переданы. Такое соединение называется "канал передачи данных", уникальный для каждого передаваемого файла.

TIdGopher и TIdGopherServer

Эти компоненты предназначены для обеспечения сетевого протокола, вытесненного в последнее время из WWW (World Wide Web) протоколом HTTP. Сервер, реализующий этот протокол, обеспечивает иерархическую распределенную систему поддержки документооборота. Пример использования этой пары компонентов, находящийся в директории demosindyGopherClient и demosindy GopherServer, демонстрирует, как при помощи этого протокола можно предоставлять в локальной сети информацию о файлах, находящихся на вашем компьютере, в том числе и о закрытых.

TIdHostNameServer

Серверный компонент, предназначенный для передачи клиентам локального имени сервера.

TIdHTTP и TIdHTTPServer

Компоненты используются для обеспечения сетевого протокола HTTP (поддерживаются версии 1.0 и 1.1, включая операции GET, POST и HEAD). Кроме того, обеспечивается поддержка аутентификации и применения proxy-серверов. Серверный компонент используется для предоставления услуг другому Web-серверу, поддерживающему данный протокол. TIdHTTPServer облегчает реализацию таких функций, как cookies, управление состояниями и др.

TIdIcmpClient

Клиентский компонент, предназначенный для обеспечения протокола ICMP (Internet Control Message Protocol), с помощью которого осуществляется выполнение операции ping и трассировка сети.

Клиентский компонент, предназначенный для обеспечения протокола POP (Post Office Protocol), включая поддержку MIME-кодирования и декодирования, а также передачу многобайтных символов.

TIdIMAP4Server

Серверный компонент, предназначенный для поддержки операций по протоколу IMAP (Internet Message Access Protocol) на сервере. Протокол позволяет производить поиск сообщений электронной почты на сервере. Различие протоколов IMAP и РОР заключается в том, что протоколу РОР требуется дополнительная память для хранения данных, а протокол IMAP обращается к серверу вместо клиентской машины. IMAP4 создавался для замены POP3, однако до сих пор протокол POP3 остается широко используемым стандартом.

TIdIRCServer

Серверный компонент, предназначенный для поддержки наиболее часто используемых в Интернете сервисных операций, обычно называемых chat (для дружеских бесед). Компонент обеспечивает базовые конструктивные блоки для IRC (Internet Relay Chat) сервера.

TIdMappedPortTCP

Серверный компонент, предназначенный для создания отображаемых портов, которые часто используются в proxy-серверах. Методы этого компонента позволяют отобразить один порт на другой. Например, порт 80 может быть отображен к порту 3000, и все запросы к первому порту (порт 80) будут переадресованы на второй порт (порт 3000).

TIdNNTP и TIdNNTPServer

Эти компоненты необходимы для обеспечения сетевого протокола NNTP (Network News Transfer Protocol), используемого в службах новостей. Клиентский компонент включает поддержку MIME-кодирования и декодирования, а также поддержку многобайтных символов и альтернативных кодировок. Серверный компонент позволяет создавать серверы новостей. Важно отметить, что TIdNNTPServer является не полнофункциональным сервером новостей, а компонентом, обеспечивающим базовые возможности для такого сервера.

TIdQOTD и TIdQOTDServer

Компоненты используются для обеспечения службы "цитат дня" (Quote of the Day). С помощью клиентского компонента осуществляется соединение с экземпляром серверного компонента для получения ежедневной цитаты. Каждый экземпляр сервера содержит уникальную базу данных цитат.

Клиентский компонент, предназначенный для применения в приложениях протокола SMTP (Simple Mail Transfer Protocol), обеспечения поддержки аутентификации, MIME-кодирования и декодирования, а также для поддержки многобайтных символов.

Клиентский компонент, предназначенный для обеспечения протокола SNTP (Simple Network Time Protocol) - службы времени. Может использоваться для соединения с любой службой времени с целью определения текущих даты и времени.

TIdSimpleServer

Серверный компонент, обеспечивающий облегченный ТСР-сервер. Позволяет организовывать соединение "точка-точка". Используется для создания серверов с единственным пользователем, то есть может единовременно обслуживать только одно подключение. В отличие от компонента TIdTCPServer не порождает вторичные процессы при ожидании запросов от клиентов и при обработке этих запросов. Другими словами, если сервер обслуживает запрос от какого-то клиента, а в это время к нему обращается для подключения другой клиент, то он будет блокирован до конца обработки первого запроса.

TIdTelnet и TIdTelnetServer

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

TIdTime и TIdTimeServer

Клиентский компонент является альтернативой компонента TIdSNTP для определения времени. Важно отметить, что форматы этих двух протоколов различны. TIdTime основан на формате RFC 868 (возвращает время во внутреннем стандарте ОС UNIX, выполняя все необходимые преобразования). Серверный компонент подобен по функционированию DayTime-серверу. Может использоваться для реализации службы времени на локальном компьютере. Дополнительного кода не требуется, достаточно создать экземпляр TIdTimeServer, который будет возвращать время внутренних часов серверного компьютера.

TIdTrivialFTP и TIdTrivialFTPServer

Эти компоненты необходимы для организации простейшего протокола передачи файлов. Клиентский компонент этого протокола используется для соединения с экземпляром соответствующего серверного компонента. Протокол предназначен для частных, облегченных, локальных случаев передачи файлов, например в локальных вычислительных сетях или для загрузки (выгрузки) таблиц маршрутизации в маршрутизаторы. Ввиду ослабленных характеристик этого протокола его использование не рекомендуется в случае применения алгоритмов аутентификации или любых других механизмов защиты. Основное назначение данного протокола - передача файлов аппаратному устройству с целью его модификации.

TIdTunnelMaster и TIdTunnelSlave

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

TIdWhois и TIdWhoIsServer

Этот клиентский компонент осуществляет соединение с любым стандартным Whois-сервером, позволяющим получить информацию о доменах. Серверный компонент обеспечивает базовую функциональность NIC сервера.

Indy Misc

Страница палитры компонентов Indy Misc (Indy Miscellaneous Components) включает кодеки BASE64, UUE, Quoted Printable и другие распространенные форматы обмена данными через e-mail, кодеры (MD2, MD4 и MD5) для стандартов криптографии, используемые для хранения паролей и электронных подписей в необратимом (трудно поддающемся дешифрованию) виде, а также многие другие полезные компоненты и утилиты, часто применяемые при разработке Интернет-приложений.

TIdAntiFreeze

Вследствие блочной организации алгоритмов компонентов Indy зачастую создается впечатление, что приложение "зависло", в то время как соединение работает. Чтобы исключить использование вторичных процессов (threads) при организации коммуникаций для предотвращения замораживания (freeze) приложения, достаточно поместить на форму указанный компонент.

Компонент работает, анализируя запросы из стека протокола TCP/IP и посылая сообщения приложению во время задержки при возникновении блокировки внешних соединений, что создает иллюзию работающего кода. Поскольку воздействие компонента осуществляется на блокированные соединения только для главного процесса, использование TIdAntiFreeze во вторичных процессах приложения не требуется. Необходимо помнить, что компонент TIdAntiFreeze замедляет работу соединений, поскольку работа главного процесса периодически прерывается для обработки сообщений. Отсюда следует, что надо заботиться о том, чтобы разрабатываемое приложение не тратило слишком много времени на обработку сообщений, включая OnClick, OnPaint, OnResize и др. В какой-то степени этим можно управлять через свойства класса TIdAntiFreeze. Использование данного компонента не является обязательным, но позволяет решить проблему синхронизации соединений с визуальным интерфейсом приложения.

TIdDateTimeStamp

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

TIdIPWatch

Это компонент, основанный на таймере, который постоянно контролирует изменения в IP-адресе компьютера. События компонента возникают, когда выявлено изменение. Указанный компонент обычно используют для обнаружения факта появления связи компьютера с Интернетом или любой другой сетью. Изменение в IP-адресе в этой ситуации может произойти из-за назначения IP-адреса DHCP-сервером (Dynamic Host Configuration Protocol) при соединении с новой сетью.

TIdLogDebug

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

TIdMessage

Компонент используется в комбинации с другими компонентами, чтобы должным образом расшифровать или кодировать сообщения. Это могут быть POP-, SMTP- и NNTP-компоненты. Класс поддерживает MIME-шифрование и расшифровку, многобайтные символы и кодировку ISO.

TIdNetworkCalculator

Один из немногих компонентов Indy, который можно использовать при конструировании приложений. Сетевой калькулятор может служить для вычислений, производимых над IP-адресами, включая сетевые маски, подсеть, классы сети и т.д.

TIdThreadMgrDefault

Компонент обеспечивает управление вторичными процессами по умолчанию. Создается в случае, если для какого-либо компонента Indy, поддерживающего управление процессами, не определен экземпляр класса TIdThreadManager. Компонент обеспечивает только основные возможности управления вторичными процессами: создает и уничтожает их по требованию.

TIdThreadMgrPool

Более продвинутый компонент управления процессами, чем TIdThreadMgrDefault, потому что он объединяет процессы, а не создает или уничтожает их по требованию.

TIdVCard

VСard - электронный эквивалент визитной карточки, может содержать персональную информацию владельца, графические данные.

TIdIMFDecoder

Предназначен для декодирования Интернет-сообщений. Является наследником класса TIdCoder, так же как и все остальные компоненты-кодировщики. Класс TIdCoder осуществляет декодирование в соответствии со стандартом формата текстовых Интернет-сообщений ARPA RFS-822, предложенным в августе 1982 года, и стандартом для обмена USENET-сообщениями RFC 1036, предложенным в декабре 1987 года.

Компонент расширяет возможности класса TIdCoder, позволяя обнаруживать формат RFS-822 по контексту заголовков, обеспечивая режим расшифровки при приеме и MIME-шифрование и расшифровку. Компонент TIdIMFDecoder используется в классе TIdMessageClient для декодирования получаемых и передаваемых сообщений.

TIdQuotedPrintableEncoder

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

TIdBase64Encoder

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

TIdUUEncoder

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

TIdXXEncoder

Этот метод шифрования едва ли когда-либо будет использоваться. По сути, это то же самое UU-кодирование, но с другой таблицей шифрования.

TIdCoderMD2

Компоненты с различными разновидностями алгоритма шифрования MD (Message Digest). Все они основаны на перемешивании, являются односторонними и не имеют алгоритмов расшифровывания.

Компоненты протокольных клиентов и серверов могут быть использованы для разработки серверных и клиентских Интернет-приложений, совместно или взамен базовых (ClientSocket, ServerSocket) и других компонентов из состава палитры Internet и Fastnet. Компоненты Indy не используют архитектуру WebBroker, реализуя поддержку Интернет-протоколов и служб на нижнем уровне непосредственно в своем исходном коде (исходные коды прилагаются).

TIdConnectionInterceptOpenSSL и TIdServerInterceptOpenSSL

Протокол SSL - Secure Sockets Layer (Секретный Уровень Сокетов), обеспечивающий секретность и надежность связи между двумя приложениями, имеет два уровня. На низком уровне многоуровневого транспортного протокола (например, TCP) SSL является протоколом записи и используется для инкапсуляции различных протоколов более высокого уровня. Преимущество SSL состоит в том, что он является независимым протоколом прикладной программы, при этом протокол более высокого уровня может быть использован поверх SSL.

SSL осуществляет защиту связи, которая имеет три основные функции: обеспечение конфиденциального соединения; шифрование с открытым ключом (используется для подтверждения подлинности адресата); поддержка надежности передачи данных.

  • Симметричная криптография используется для шифрования данных (например, DES, RC4 и т.д.).
  • Цифровая подпись обеспечивается при помощи асимметричного шифрования с открытым ключом (например, RSA, DSS и т.п.).
  • Надежность связи, транспортировка сообщения включает проверку целостности сообщения посредством корректирующих кодов MAC, безопасных хеш-функций (например, SHA, MD5, и т.д.) с использованием MAC-вычислений.

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

Компоненты TIdConnectionInterceptOpenSSL и TIdServerInterceptOpenSSL обеспечивают соединение как со стороны клиента, так и со стороны сервера в соответствии с протоколом SSL. Необходимо отметить, что компоненты TIdConnectionInterceptOpenSSL и TIdServerInterceptOpenSSL есть только в Delphi 6, а в Kylix отсутствуют. Это связано со сложностью протокола, который в случае реализации Windows основан на функциях операционной системы.

Примеры использования компонентов Indy можно найти в каталогах /Delphi6/Demos/Indy. Всего библиотека Indy в версии 8.0 содержит 69 компонентов. Заявлено, что в версии 9.0 указанная библиотека будет содержать 86 компонентов. Все компоненты унифицированы и включены как в Delphi 6, так и в Kylix, что позволяет использовать их для разработки кросс-платформенных приложений. Все компоненты Indy поддерживают многопоточность.

В компонентах Indy реализована почти вся функциональность, имеющаяся в компонентах Internet и Fastnet, что наглядно показано в таблице.

Компоненты Fastn et Компоненты Indy Назначение компонентов
1 TserverSocket, TClientSocket TIdTCPserverSocket, TIdTCPClientSocket Взаимодействие двух компьютеров (клиента и сервера) с помощью протокола TCP/IP
2 TNMDayTime TIdDayTime, TIdDayTimeServer Запрос сервера о текущем времени
3 TNMEcho TIdEcho, TIdEchoServer Используются для связи с сервером отклика
4 TNMFinger TIdFinger, TIdFingerServer Используются для получения информации о пользователе с поискового Интернет-сервера
5 TNMFTP TIdFTP, TIdTrivialFTP, TIdTrivialFTPServer Обеспечивают передачу файлов с помощью протокола FTP
6 TNMHTTP TIdHTTP, TIdHTTPServer Используют протокол HTTP для обмена данными
7 TNMMsgServ, TNMMsg Используются для передачи простых текстовых сообщений от клиента к серверу
8 TNMNNTP TIdNNTP, TIdNNTPServer Поддерживают обмен данными с сервером новостей
9 TNMPOP3 TIdPOP3 Используются для получения электронной почты с почтового сервера с помощью протокола POP3
10 TNMSMTP TIdSMTP Используются для отправки электронной почты через почтовый сервер Интернет
11 TNMStrm, TNMStrmServ Передают двоичные данные, записанные в поток, с помощью протокола TCP/IP
12 TNMUDP TIdUDP, TIdUDPServer Осуществляют пересылку данных с использованием протокола UDP
13 TpowerSock, TNMGeneralServer Инкапсулированные в виде компонентов классы, которые являются базовыми для написания собственных клиентов (Powersock) и серверов (NMGeneralServer)
14 TNMUUProcessor TIdUUEncoder, TIdUUDecoder Осуществляют перекодировку двоичных файлов в формат MIME или UUENCODE
15 TNMURL Перекодирует строки в формат HTML и осуществляет обратную перекодировку

Исключение составляют такие классы, как TNMMsgServ, TNMMsg, TNMStrm, TNMStrmServ, TpowerSock, TNMGeneralServer, TNMURL, которые либо реализуют морально устаревшие протоколы, либо обладают функциональностью, реализованной в большой группе альтернативных классов.

Однако в отличие от своих предшественников - компонентов Internet и Fastnet, в Indy богаче представлены серверные компоненты и компоненты перекодирования и шифрования данных, а также поддержка аутентификации (палитра Indy Misc). Как видно из приведенной выше таблицы, основные протоколы и службы обеспечиваются не только клиентскими, но и серверными компонентами. Это службы времени, отклика, получения информации о пользователе, а также протоколы HTTP, NNTP, UDP и даже простейший вариант FTP.

Некоторые примеры применения компонентов Indy

В компонентах Indy, которые содержатся в Delphi, IP-адрес определяется в свойстве Host, как правило, только в клиентских приложениях. Компоненты, размещаемые на сервере, имеют методы, позволяющие начать или прекратить опрос соответствующего порта, - например изменение свойства Active компонента IdTCPServer начинает или прекращает опрос соответствующего порта. После установки связи между клиентом и сервером можно начинать передачу данных.

В компонентах Indy большое внимание уделяется безопасности и надежности при работе с данными. Например, в компоненте IdTCPClient есть методы Connect и Disconnect. Применяя технику программирования, как в приведенном ниже коде со стороны клиента:

With TCPClient do begin Connect; try lstMain.Items.Add(ReadLn); finally Disconnect; end; end;

и используя свойство Connection, передаваемое в качестве параметра экземпляра AThread класса TIdPeerThread, со стороны сервера:

With AThread.Connection do begin WriteLn("Hello from Basic Indy Server server."); Disconnect; end;

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

Обратите внимание на методы ReadLn и WriteLn соответствующих классов - они напоминают стандартные операторы ввода-вывода Pascal. Это дань технике программирования в UNIX, где большинство системных операций выполняются благодаря чтению и записи в соответствующие файлы.

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

Procedure TForm1.IdECHOServer1Connect(AThread: TIdPeerThread); begin lblStatus.caption:= "[ Serving client ]"; end;

В Indy представлены компоненты, реализующие протоколы с клиентскими и серверными частями, присущие только этой библиотеке. Компоненты TIdGopherServer и TIdGopher, благодаря методам GetExtendedMenu, GetFile, GetMenu, GetTextFile на клиентской стороне и ReturnGopherItem, SendDirectoryEntry - на стороне сервера, помогают осуществить просмотр файлов различного типа, в том числе помеченных как скрытые, а также директорий на удаленном компьютере (подобно тому, как это делает команда dir *.* в операционной системе MS-DOS).

При помощи компонентов IdSMTP и IdMessage можно легко создать свое Web-приложение, способное отправлять почту по протоколу SMTP.

При этом класс IdMessage (один из 23 компонентов со страницы Indy Misc) отвечает за формирование сообщения, что вытекает из его названия, а IdSMTP - за организацию соединения с почтовым сервером.

Технология, применяемая в Indy, использует операции чтения и записи с блокировкой. Любая операция Connect, используемая в Indy, ожидает завершения соединения. При работе с клиентскими компонентами Indy, как правило, требуется выполнение следующих операций:

  • запросить соединение с сервером;
  • осуществить запросы к серверу на чтение и запись (в зависимости от типа сервера шаг выполняется единожды или повторяется много раз);
  • закончить соединение с сервером и разъединиться.

Компоненты Indy разрабатывались так, чтобы обеспечить сверхвысокий уровень абстракции. Запутанность и подробности стека TCP/IP скрыты от программиста, с тем чтобы он мог сосредоточиться на текущих задачах.

Следующий небольшой пример показывает типичную сессию клиентского компонента:

With IndyClient do begin Host:= "zip.pbe.com"; // Host to call Port:= 6000; // Port to call the server on Connect; try // Your code goes here finally Disconnect; end; end;

В примере, даже если соединение с сервером не будет установлено, связь корректно разорвется благодаря использованию оператора try-finally.

Серверные компоненты Indy описывают разнообразные модели серверов, которые можно использовать в зависимости от потребностей и применяемого протокола.

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

Иными словами, для каждого клиентского подключения класс TIdTCPServer использует уникальный вторичный поток, вызывая обработчик события OnExecute этого потока. Формальным параметром метода OnExecute является ссылка на экземпляр класса Athread, соответствующего созданному потоку. Свойство Connection этого класса - ссылка на класс TIdTCPConnection, экземпляр которого создается для обработки клиентского запроса. TIdTCPConnection поддерживает чтение и запись через соединение, а также установление и завершение сеанса связи.

Протокол UDP работает без предварительной установки соединения с сервером (каждый посланный пакет является самостоятельным набором данных, а не частью большой сессии или соединения). В то время как TIdTCPServer порождает отдельные потоки для каждого соединения, TIdUDPServer использует или главный поток, или единственный вторичный поток, который обрабатывает все запросы протокола UDP. Когда TIdUDPServer активен, создается поток для прослушивания входящих UDP-пакетов. Для каждого полученного пакета возникает событие OnUDPRead или в основном потоке, или в контексте прослушивающего потока - в зависимости от значения свойства ThreadedEvent. Когда ThreadedEvent принимает значение False, событие возникает в основном потоке, в противном случае - в прослушивающем потоке. Пока происходит обработка события, другие операции сервера блокируются. Поэтому важно следить, чтобы процедуры OnUDPRead выполнялись как можно быстрее.

Если нужно создать клиентское приложение нового клиента для существующего сервера с использованием существующего протокола, ваша задача состоит исключительно в разработке и отладке клиентского приложения. Однако, когда приходится разрабатывать и клиентское, и серверное приложения с применением существующего или нового протокола, мы сталкиваемся с классической проблемой "яйца и курицы". С чего начинать программирование - с клиента или с сервера?

Очевидно, в итоге должны быть созданы и клиент, и сервер. Для многих приложений, особенно использующих текстовый протокол (например, HTTP), проще начать создание приложения с проектирования сервера. А для его отладки имеется удобный клиент, который уже существует. Это - консольное приложение Telnet, которое имеется и на Windows, и на UNIX.

Если набрать консольную команду telnet 127.0.0.1 80 с IP-адресом локального компьютера и номером порта 80, используемым по умолчанию Web-серверами, то приложение откликнется текстом, представленным на рис. 6, в случае ОС Windows 2000 и IIS 5.0.

Для создания самого простого сервера с использованием компонентов Indy необходимо:

Если необходимо спроектировать сервер, который будет не только корректно информировать своих клиентов о разрыве соединения, но и выдавать для них информацию о возникших ошибочных ситуациях, применяйте оператор try-except вместо try-finally - например, как показано в следующем примере:

Procedure TDataModule1.IdTCPServer1Execute(AThread: IdPeerThread); var s: String; begin with AThread.Connection do try try s:= ReadLn; // Perform the task of the server here // if no exception is raised, // write out the server"s response WriteLn(s); except on e: Exception do begin WriteLn(e.Message); end; //on end; //try except finally Disconnect; end; end;

Этот небольшой пример демонстрирует этапы создания простого текстового сервера, а также способы его отладки.

Вышеописанный сервер является типичным примером организации современного распределенного вычисления.

Особенности создания многозвенных приложений

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

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

Итак, мы приступаем к разработке приложения с трехзвенной архитектурой. Для создания сервера базы данных с использованием компонентов Indy необходимо:

  1. Создать новый проект.
  2. Поместить на главную форму проекта экземпляр компонента TIdTCPServer с палитры Indy Servers.
  3. Присвоить свойству DefaultPort экземпляра класса TIdTCPServer1 значение 6001 (рекомендуется присваивать большие значения, чтобы избежать дублирования номеров портов у различных приложений), а свойству Active - значение true.
  4. Добавить в проект новый модуль, выбрав команду File | New | Data Module, и поместить на него экземпляры компонентов SQLConnection и SQLDataSet с закладки dbExpress на палитре компонентов.
  5. Установить свойство ConnectionName класса SQLConnection в IBLocal и LoginPrompt в False. Если вы не конфигурировали IBLocal на базу данных employee.gdb, сначала проделайте эту процедуру.

Серж Досюков (Serge Dosyukov) Майк Фэм (Mike Pham)

В статье рассказывается о том, как создать автономную Web-службу, используя комплект Indy и Delphi 7 и как использовать комплект Indy для осуществления поддержки в Delphi 7 Web-служб на основе протокола SOAP. За дополнительной информацией о создании Web-служб рекомендуем обратиться к великолепной статье Ника Ходжеса (Nick Hodges) на сайте сообщества Borland: "Шекспир в сети" .

Рано или поздно может возникнуть необходимость создания сервера, который являлся бы автономным HTTP-сервером и осуществлял поддержку Web-служб. Например, может понадобиться создать сервер приложений на основе протокола SOAP для n-уровневого приложения, созданного с помощью Delphi.

Введение

Интерактивная справка Delphi предоставляет великолепную последовательную инструкцию о том, как создать Web-службу, MIDAS-сервер (COM, DCOM-модель), но в ней практически отсутствует информация о создании автономного n-уровневого MIDAS-приложения на основе протокола SOAP.

Ранее была опубликована Дэйва Нотажа (Dave Nottage). В этой статье была описана идея о том, как создать в Delphi 6 Web-службу с поддержкой SOAP и возможностью публикации SOAP-интерфейсов модуля Datamodule, то есть эта статья позволяла научиться создавать собственные n-уровневые MIDAS-системы.

Выпущенные компанией Borland Delphi 7 и новый комплект Indy обладают встроенной поддержкой такой функциональности.

Однако, несмотря на встроенную поддержку, документальное описание этой возможности отсутствует.

Недавние сообщения в сетевой конференции Borland и поиск в сети с помощью сервера Google, позволили авторам разработать способ преобразования существующего кода из Delphi 6 в Delphi 7. Но - всему свое время.

Основная идея

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

  • быть автономным HTTP-сервером;
  • использовать Indy в качестве платформы;
  • поддерживать публикацию по протоколу SOAP;
  • быть способным к публикации SOAP-модулей DataModules, что позволило бы создать собственный n-уровневый сервер на основе SOAP/HTML.

HTTP-сервер и SOAP

Многие знают Indy и использовали компоненты THTTPServer раньше. Несложно поместить этот компонент на форму приложения, но как заставить его поддерживать SOAP? В каталоге "C:Program FilesBorlandDelphi7SourceIndy" можно найти файл IdHTTPWebBrokerBridge.pas. Это как раз то, что нужно.

Этот файл не является частью исполняемого модуля Indy, поэтому нужно включить его в текущий проект в качестве стандартного проектного файла. (Для компиляции проекта также понадобится файл IdCompilerDefines.inc.) Данные файлы необходимо скопировать в каталог текущего проекта. Для увеличения скорости может потребоваться изменения кода, так что эти файлы лучше хранить отдельно от дистрибутива Indy.

Далее описывается реализация замещения компонента из THTTPServer, расширенного для поддержки пакетов SOAP и называющегося TIdHTTPWebBrokerBridge. Эта конструкция является классом, наследуемым от TCustomHTTPServer и поддерживающим базовую привязку запросов.

Так как этот класс недоступен из палитры, необходимо будет определить его как регулярный объект при выполнении программного кода.

Этот объект можно использовать точно таким же образом, как и обычный THTTPServer, за исключением тех дополнительных свойств, которые обеспечивают работу с SOAP.
Однако, сначала рассмотрим подготовку необходимого кода.

WebBroker и Indy

Тем, кому раньше приходилось создавать Web-службы, известно, что для этого используется WebBroker . Delphi 7, также как и Delphi 6, использует архитектуру WebBroker для поддержки SOAP.

Поэтому нужно создать модуль TWebModule и поместить в него следующие три компонента: THTTPSoapDispatcher, THTTPSoapPascalInvoker и TWSDLHTMLPublish. Все они доступны из вкладки WebServices палитры компонентов. После связывания SOAPDispatcher с SOAPPascalInvoker форма приложения готова. В качестве конечного результата должно получится нечто вроде того, что изображено на следующем рисунке:

(модуль uWebModule.pas)

Лучше все оставить как есть, так как нет необходимости изменять или исполнять какой-либо собственный код для данной формы.

WebModule и Indy

Перейдем к другой части кода, необходимой для реализации HTTP-сервера.

Как можно заметить TIdHTTPWebBrokerBridge обладает методом RegisterWebModuleClass, который позволяет зарегистрировать собственный модуль WebModule и сделать его доступным для сервера.

Таким образом, после создания серверного объекта fServer, нужно просто вызвать класс fServer.RegisterWebModuleClass (TwmSOAPIndy).

Примечание. При обычной реализации TIdHTTPWebBrokerBridge объект TwmSOAPIndy будет создаваться каждый раз когда приходит запрос. Очевидно, что в этом нет необходимости. Поэтому класс можно модифицировать так, чтобы обеспечить перманентное создание данного объекта в течении времени пока существует объект Server. За дополнительной информацией рекомендуется обратиться к документации о реализации классов.

Готов ли сервер?

© 2024 ermake.ru -- Про ремонт ПК - Информационный портал