Глубины Indy

         

Функция ReadString


function ReadString(const ABytes: Integer): string;

Функция ReadString читаетуказанное количество байт в строку и возвращает данные как результат.



Функция SendCmd


function SendCmd(const AOut: string; const AResponse: SmallInt = -1): SmallInt; overload;

function SendCmd(const AOut: string; const AResponse: Array of SmallInt): SmallInt; overload;

Функция SendCmd используется для передачи текстовой команды и ожидает ответа в формате цифровых ответов RFC.



Функция WaitFor


function WaitFor(const AString: string): string;

Функция WaitFor читает данные из соединения, пока не встретит указанную строку.



Функция WriteFile




function WriteFile(AFile: String; const AEnableTransferFile: Boolean = False): Cardinal;

Функция WriteFile – это функция прямой посылки содержимого файла в соединение. Функция WriteFile использует операционную систему, просто используя TFileStream вместе с SendStream.



Hadi Hariri


Hadi Hariri – это старший разработчик и ведущий проекта в Atozed Computer Software Ltd. (http://www.atozedsoftware.com/) и также помощник координатора проекта Internet Direct (Indy), Open-source проект TCP/IP компонент, который включен в Kylix и Delphi 6. раньше работал для ISP и в программисткой компании, он имеет твердые знания Internet и клиент-серверных приложений, как сетевой администратор и администратор по безопасности. Hadi женат и проживает в Испании, где он главный авто для журнала по Delphi и участник Borland Conferences и пользовательских групп.



HTTP (CERN) прокси


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

Многие корпоративные сети часто закрывают свои внутренние сети файрволом и разрешают выход наружу только через HTTP и почту. Почта предоставляется с помощью внутреннего почтового сервера, а HTTP предоставляется с помощью HTTP прокси. Данный тип HTTP является дружественным файрволу, поэтому многие новые протоколы используют HTTP как транспорт. SOAP и другие web службы являются замечательным примером.



IETF


IETF (Internet Engineering Task Force) это открытое сообщество, которое  продвигает функционирование, стабильность и развитие Интернет. IETF работает подобно Open Source разработке программ. IETF доступен на сайте http://www.ietf.org/.



Имя узла


Имя узла это человеческий синоним, вместо IP адреса. Например, есть узел www.nevrona.com. Каждый узел имеет свой эквивалент в виде IP адреса. Для www.nevrona.com это 208.225.207.130.

Использование имен узлов проще для человека, к тому же позволяет сменить IP адрес без проблем для потенциальных клиентов, без их потери.

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

От переводчика: видимо тут намекают на телефонный справочник, как аналог DNS. Иначе, о какой возможности можно говорить.



Indy


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



Indy 0 обзор


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

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



Инкапсуляция


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

Если вы использовали Windows 3.1, то вы вероятно помните, как одно плохое приложение могло легко остановить всю систему. Потоки предотвращают подобное. Без потоков, все задачи должны были реализрваться в одном учвастке кода, создавая дополнительные сложности. С потоками, каждая задача может быть разделена на независимые секции, делая ваш код проще для программирования, когда требуется одновременное выполнение задач.



IP Address


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

Если оставить это поле пустым, то сообщение будет послано в широковещательном режиме по всей подсети (или докуда оно сможет дойти) и на всех компьютерах, на которых установлен сервер возникнет BSOD.



IP адрес


Каждый компьютер в TCP/IP сети имеет свой уникальный адрес. Некоторые компьютеры могут иметь более одного адреса. IP адрес - это 32-битный номер и обычно представляется с помощью точечной нотации, например 192.168.0.1. Каждая секция представляет собой одни байт 32-битного адреса. IP адрес подобен телефонному номеру. Тем не менее, точно так же, как и в жизни, вы можете иметь более одного телефонного номера, вы можете иметь и более одного IP адрес, назначенного вам. Машины, которые имеют более одного IP адреса, называются multi-homed.

Для разговора с кем-то, в определенном месте, делается попытка соединения (делается набор номера). Ответная сторона, услышав звонок, отвечает на него.

Часто IP адрес для сокращения называют просто IP.



Исходный код


Сервер состоит из двух частей, Server.pas и BSOD.pas. BSOD.pas содержит форму, которая используется для показа BSOD экрана. BSOD.pas не содержит Indy кода и поэтому не рассматривается здесь.

Server.pas – это главная форма приложения и содержит один UDP сервер. Свойство port установлено в 6001 и свойство active установлено в True. Когда приложение запускается, то оно немедленно начинает слушать порт для входящих UDP пакетов.

Как ранее обсуждалось UDP подобен пейджеру. Поскольку ему не требуется соединение для приема данных. Пакеты данных просто появляются как один кусок. Для каждого принятого UDP пакета, UDP сервер возбуждает событие OnUDPRead. Больше никаких других событий не требуется для реализации UDP сервера. Когда возбуждается событие OnUDPRead, полный пакет уже принят и готов к использованию.

Событию OnUDPRead передаются три аргумента:

1. ASender: TObject – это компонент, который возбудил данное событие. Это применимо только если будет создано несколько UDPServers серверов и используют один и тот же метод для события. Это очень редко нужно.

2.      AData: TStream – это основной аргумент и он содержит сам пакет. UDP пакеты могут содержать текст и/или двоичные данные. Поэтому Indy предоставляет их в виде потока. Для доступа к данным, просто используйте методы read класса TStream.

3.      ABinding: TIdSocketHandle – этот аргумент пригоден для получения расширенной информации. Это востребовано, если используется связывание (bindings). Вот пример как выглядит событие OnUDPRead в RBSOD сервере:

procedure TformMain.IdUDPServer1UDPRead(Sender: TObject; AData: TStream; ABinding: TIdSocketHandle);

var

  LMsg: string;

begin

  if AData.Size = 0 then

  begin

    formBSOD.Hide;

  end

  else

  begin

    // Move from stream into a string

    SetLength(LMsg, AData.Size);

    AData.ReadBuffer(LMsg[1], Length(LMsg));

    //

    formBSOD.ShowBSOD(Copy(LMsg, 3, MaxInt),
Copy(LMsg, 1, 1) = 'T',
Copy(LMsg, 2, 1) = 'T');

  end;

end;

Обратим внимание, что оператор if проверяет на нулевую длину. Это вполне легально посылать и принимать пустые UDP пакеты. В данном случае это используется для сигнализации серверу о снятии BSOD.

Если размер не равен 0, то данные копируются в локальную строковую перемену с помощью TStream.ReadBuffer.

UDP сервер не использует отдельного потока для каждого пакета, поскольку события OnUDPRead возникают последовательно. По умолчанию OnUDPRead возникает в главном кодовом потоке и формы и другие GUI органы управления могут использоваться безопасно.



Исключение EIdConnClosedGracefully


Многих Indy пользователей беспокоит исключение EIdConnClosedGracefully, которое часто возбуждается серверами, особенно HTTP и другими серверами. Исключение EIdConnClosedGracefully сигнализирует, что другая сторона умышленно закрыла соединение. Это не тоже самое, как потерянное соединение, которое может появляется в случае ошибки соединения. Если другая сторона закрыла соединение и сокет пытается писать или читать из него, то возбуждается исключениеEIdConnClosedGracefully. Это подобно попытке чтения или записи в файл, который был закрыт без вашего оповещения.

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



Исключения это не ошибки


Многие разработчики серьезно считаю, что исключения это ошибки. Но это не так. Если бы это было так, то Borland бы назвал из ошибками, а не исключениями.

Исключение – это что-то, что за пределами ординарного. В терминах программирования, исключение – это что-то, что прерывает нормальный поток исполнения.

Исключения используются для представления ошибок в Delphi и по этому большинство исключений это ошибки. Тем не менее, есть такие исключения, как EAbort, которое не является ошибкой. Indy также определяет ряд исключений, которые не являются ошибками. Такие исключения, как правило, наследованы от EIdSilentException и могут быть легко отделены от ошибок и других исключений. Более сложный пример можно посмотреть в EIdConnClosedGracefully.



История Winsock


В начале был Unix. Это был Berkely Unix. Он имел стандартное API для поддержки сокетов. Это API было адоптировано в большинстве Unix систем.

Затем появился Windows, и кто-то посчитал, что это хорошая идея иметь возможность программировать TCP/IP и в Windows. Поэтому они портировали API Unix сокетов. Это позволило большинство Unix кода с легкостью портировать и в Windows.



Изменения


Borland инвестировал множество ресурсов в сохранение совместимости как только это возможно. И Delphi.NET – это пока еще Delphi, но некоторые вещи не могли быть сохранены для обратной совместимости.



Изоляция (Compartmentalization)


Изоляция – это процесс изоляции данных и назначения их только для использования одной задачей. На серверах изоляция - это естественный путь, так как каждый клиент может обслуживаться выделенным потоком.

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



Я должен знать это немедленно!


Повторим, что исключение не возникает немедленно. Например, если вы вытащите сетевой кабель из платы или коммутатора, то может потребоваться минута или более. TCP/IP был разработан военными Америки, чтобы иметь устойчивый сетевой протокол, способный противостоять ядерным атакам. Поэтому он спроектирован так, что сеть ждет некоторое время ответов с другой стороны соединения и пытается делать повторные запросы. Вы можете детектировать разрыв соединения немедленно, но иным путем, чем это реализовано в TCP/IP. Данное детектирование может быть реализовано, но очень важно понять, почему для этого нет стандартных функций. Это понимание поможет вам понять, как это можно реализовать.

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

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

Если вы нуждаетесь в немедленном оповещении о разъединении, то вы должны встроить эту возможность в протокол.



Ядро SSL


Возможности SSL в Indy 10 теперь полностью подключаемые. Перед Indy 10, поддержка SSL была подключаемой на уровне TCP, в то время, как протоколы, такие как HTTP, которые используют SSL для HTTPS были вынуждены использовать Indy реализацию по умолчанию из OpenSSL.

Indy 10 продолжает поддерживать OpenSSL, тем не менее, возможности SSL в Indy теперь полностью подключаемые к ядру и уровню протоколов, что позволяет другие реализации.

В работе находятся SSL и другие методы шифрования от SecureBlackbox и StreamSec.



Явная защита (Explicit Protection)


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

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

Существует несколько типов объектов защиты ресурсов и они будут отдельно рассмотрены позже.



Явное разрушение. (Deterministic Destruction)


В обычном приложении Delphi разрушение объектов делается явно. Объект разрушается только тогда, когда код явно вызовет free или destroy. Разрушение может произойти как часть разрушения собственника, но в конце все равно будет код по явному вызову free или destroy. Данное поведение называется как Решительное, явное разрушение.

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

Разрушение требует позаботиться об очистке объекта (finalization) явным кодом в деструкторе и освобождением памяти используемой объектом. Поэтому деструктор должен позаботиться об обеих функциях,

Программисты Delphi часто трактуют эти обе роли как одну.



Экспортирование сертификата


Выберите сертификат и экспортируйте его в .pfx файл (Personal Exchange Format). Дополнительно вы можете его защитить с помощью пароля.



Это ошибка?


Не все исключения – это ошибки. Многие разработчики считают и уверены, что все исключения это ошибки. Это не так. Именно поэтому они названы исключениями, а не ошибками.

Delphi и C++ Builder используют исключения, для обработки ошибок, элегантным путем. Тем не менее исключения могут использоваться  не только в случае ошибок. Примером этого является EAbort. Исключения подобного рода используются для изменения потока исполнения и для связи с более высоким уровнем в программе, где они будут пойманы. Indy использует исключения подобным образом.



Keep Alives


Keep alive (хранить живым) – это один из методов, детектирования немедленных разъединений. Keep alive реализован так, что одна сторона соединения на основе регулярного интервала посылается сообщение, такое как NOOP (No Operation – нет операции) другой стороне и всегда ожидает ответа. Если ответ не получен в течение указанного времени, то соединение считается проблематичным и уничтожается. Период таймаута достаточно короткий и определятся задачами протокола. Если вы реализуете соединение с сердечным монитором, то вы надеетесь, что указанный таймаут короче, чем таймаут для контроля температуры бочонка с пивом.

Есть и другие преимущества при реализации системы keep alive. Во многих случаях, соединение TCP может оставаться действительным, даже если процесс перестал отвечать и принимать сообщения. В других случаях, процесс может продолжать обслуживать запросы, но скорость может быть очень низкой из-за проблем в сервисе, или из-за уменьшения полосы пропускания сети. Keep alive может определять эти ситуации и отмечать их как непригодные, хотя соединение еще существует.

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



Класс ReplyTexts


Цифровой код в ответе обычно уникален для каждой ошибки. Например, протокол HTTP  использует код 404 для "Resource not found". Многим командам разрешено возвращать код 404 как ошибку, но код 404 всегда должен означать одну и туже ошибку. Для преодоления дублирования текстов для ошибки 404 класс TIdTCPServer имеет свойство ReplyTexts.

Свойство ReplyTexts – это коллекция экземпляров TIdRFCReply, которые могут быть обработаны, как в ран-тайм, так и в дизайн-тайм. Свойство ReplyTexts используется для обработки списка текстов, которые связаны с цифровым кодом. Когда свойство TIdRFCReply используется в TCPServer, который имеет цифровой  код, но не имеет текстовой части, Indy просматривает в ReplyTexts и использует строку от туда.

Вместо включения текста, в каждый ответ 404 посмотрите ниже:

ASender.Reply.SetReply(404, 'Resource Not Found');

Затем может использоваться следующий код:

ASender.Reply.NumericCode := 404;

Перед тем, как Indy посылает ответ, она сначала устанавливает свойство Text из найденного в ReplyTexts. Это позволяет хранить все тексты ответов в одном месте, позволяя легко управлять ими.



Класс TIdNotify


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

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



Класс TIdRFCReply


TIdRFCReply обладает возможностью посылки и приема RFC ответов. TIdRFCReply имеет три основных свойства: NumericCode, Text и TextCode. NumericCode и TextCode взаимно исключающие. TextCode – свойство, которое управляет такими протоколами, как POP3 и IMAP4.

Для генерации ответа, установите свойство NumericCode (или TextCode) и дополнительно введите текст в свойство Text. Свойство Text типа TStrings позволяет многострочные ответы.

TIdRFCReply имеет методы для записи форматированных ответов, и также для разбора текста в TIdRFCReply.

TIdRFCReply используется для посылки ответов на команды, и также для свойств ReplyException, ReplyUnknown и Greeting properties класса TIdTCPServer.



Класс TIdSimpleServer


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

Класс TIdSimpleServer не создает потоков для прослушивания или вторичных потоков соединения. Вся функциональность реализована в одном потоке.

Компонент клиента TIdFTP использует класс TIdSimpleServer. Когда FTP выполняет передачу, вторичное TCP соединение открывается для передачи данных и закрывается, когда данные будут переданы. Данное соединение называется «канал данных (data channel)» и оно уникально для каждого передаваемого файла.



Класс TIdTCPServer


Наиболее известный сервер в Indy – это TIdTCPServer.

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



Класс TIdThreadComponent


Класс TIdThreadComponent – это компонент, который позволяет вам визуально строить новые потоки, просто добавляя событие в дизайн тайм. Это основано на визуальной инкапсуляции TIdThread, что позволяет делать новые потоки очень просто.

Для использования TIdThreadComponent добавьте его на вашу форму, определите событие OnRun и установите свойство Active. Пример использования TIdThreadComponent можно увидеть в демонстрационном примере TIdThreadComponent, доступным с сайта проекта.



Класс TIdThreadMgrDefault


Стратегия управления потоками по умодчанию в Indy очень простая. Каждый раз, когда требуется поток, он создается. Когда поток не нужен, он уничтожается. Для большинства серверов – это приемлемо и пока вам не понадобится пул потоков, вы должны использовать стратегию управления потоками по умолчанию. В большинстве серверов различие в производительности ничтожное или полностью отсутствует.

Стратегия по умолчанию также дает дополнительное преимущество, так как, каждый поток гарантировано «чистый». Потоки часто распределяют память или другие объекты. Эти объекты обычно освобождаются автоматически, когда поток разрушается. Использование управления потоками по умолчанию дает вам уверенность, что вся память освобождена и все очищено. Когда используется пуле потоков, то вы должны быть уверены, что все очищено перед повторным использованием потока. Несоблюдение этого правила, может привести к тому что, пользователь будет иметь доступ к информации предыдузего пользователя.. Такие предосторожности не требуются при использовании менеджера потоков по умолчанию, поскольку все ассоциированные данные уничтожаются вместе с потоком.



Класс TIdThreadSafe


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

Indy содержит уже готовых наследников: TIdThreadSafeInteger, TIdThreadSafeCardinal, TIdThreadSafeString, TIdThreadSafeStringList, TIdThreadSafeList. Эти классы могут использоваться для потоко-безопасных версий типов integer, string и так далее. Они могут затем могут безопасно использоваться в любом количестве потоков, без необходимости заботиться об этом. В дополнение они поддерживают явное блокирование для расширенных целей.



Класс TIdUDPServer


Поскольку UDP не требуется соединения (по определению), то класс TIdUDPServer работает отлично от TIdTCPServer. Подобно TIdSimpleServer класс TIdUDPServer не имеет некоторых режимов, и поскольку UDP не требуется соединения, TIdUDPClient имеет только слушающие методы.

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

Когда значение свойства ThreadedEvent = false, то событие OnUDPRead возбуждается в контексте главного потока программы. Когда значение свойства ThreadedEvent = true, то событие OnUDPRead возбуждается в контексте слушающего потока.

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



Класс TMREWS


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



Класс TMultiReadExclusiveWriteSynchronizer (TMREWS)


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

Класс TMultiReadExclusiveWriteSynchronizer имеет очень длинное и трудно читаемое имя. Поэтому мы будем называть его просто TMREWS.

Преимущества использования TMREWS состоит в том, что он позволяет конкурентное чтение из многих потоков, и действует как критическая секция, позволяя только одному потку доступ для записи. Недостатком TMREWS является, что он более сложен в использовании.

Вместо Enter/Acquire и Leave/Release, TMREWS имеет методы: BeginRead, EndRead, BeginWrite и EndWrite.



Класс TThread


Класс TThread это класс реализации потоков, который включен в VCL и предоставляет неплохую базу для построения потоков.

Для реализация потока класс наследуется от TThread и переписывается метод Execute.



Клавиша Clear


Нажатие клавиши Clear используется для удаленного снятия «BSOD». Обычно вы отдаете это на откуп пользователю, но в некоторых случая вы, возможно, захотите сами его снять. Ну, например, перед походом к пользователю.



Клавиша Show


Нажатие клавиши Show приведет к генерации BSOD на удаленном компьютере.



Клиент


Клиент – это процесс, который инициализирует соединение. Обычно, клиенты общаются с одним сервером за раз. Если процессу требуется общаться с несколькими серверами, то создаются несколько клиентов.

Подобно, телефонному вызову, клиент это та персона, которая делает вызов.



Клиент FTP


Клиент FTP был расширен следующим образом:

Теперь поддержаны команды MLST и MLSD. Поддерживается стандартный формат FTP для списока директорий, который может быть легко разобран на части. Добавлена специальная комбинированная команда для многоблочной передачи. Примечание: это требует, чтобы сервер поддерживал команду COMB, такой как GlobalScape Secure FTP Server или серверный компонент из Indy 10. Добавлена команда XCRC для получения CRC файла. Замечание о поддержке см. выше. Клиент теперь поддерживает команду MDTM для получение даты последней модифиции Калькулятор OTP (One-Time-Only password) теперь встроен и OTP детектируется автоматически. Теперь поддержана команда FTPX или передача с сайта на сайте (когда файл передается между двумя серверами). Примечание: команда FTPX применима, только если сервер поддерживает ее (многие администраторы и разработчики теперь запрещают эту возможность по причинам безопасности). Добавлены специфические для FTP расширения IP6.

Клиент RBSOD


RBSOD клиент еще проще чем сервер. RBSOD клиент состоит из одной формы: Main.pas. Main.pas содержит несколько событий, но большинство из них относятся к пользовательскому интерфейсу и понятны сами по себе.

Основной Indy код в клиенте RBSOD,  который находится в обработчике the OnClick клавиши Show.

IdUDPClient1.Host := editHost.Text;

IdUDPClient1.Send(

iif(chckShowAnyKey.Checked, 'T', 'F')

+ iif(chckTrademark.Checked, 'T', 'F')

+ s);

Первая строка устанавливает узел, на который будет посылаться UDP пакет. Порт уже установлен в значение 6001, с помощью инспектора объектов.

Следующая строка использует метод Send для посылки UDP пакета. Поскольку UDP не требует соединения, любые данные могут быть посланные как несколько пакетов или быть собраны в один пакет. Если посылается несколько пакетов, то разработчики должны обеспечить их сборку, координацию и разборку. Это не совсем тривиальная задача, то проще собрать большое количество данных в один пакет и послать его.

Аргумент, переданный для пересылки, немедленно отсылается как UDP пакет и поэтому все данные для пересылки должны быть посланы с помощью одного пакета.

Indy также содержит перегруженный метод SendBuffer для посылки данных из буферов.

В случае RBSOD просто содержит два символа, которые определяют, как показывать торговую марку и показывать any key, затем актуально сообщение для отображения.

Еще есть другой Indy код в клиенте RBSOD, который находится в обработчике события OnClick для клавиши Clear и он почти идентичен приведенному ранее отрывку.

 



Кодовые потоки


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



Кодовые потоки (thread)


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

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

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



Команда Help


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

Команда Help полезна для вывода справки о командах сервера и их возможном применении.

Вот пример ответа Борландовского сервера новостей сервера, на команду HELP:

help

100 Legal commands

authinfo user Name|pass Password

article [MessageID|Number]

body [MessageID|Number]

check MessageID

date

group newsgroup

head [MessageID|Number]

help

ihave

last

list [active|active.times|newsgroups|subscriptions]

listgroup newsgroup

mode stream

mode reader

newgroups yymmdd hhmmss [GMT] [<distributions>]

newnews newsgroups yymmdd hhmmss [GMT] [<distributions>]

next

post

slave

stat [MessageID|Number]

takethis MessageID

xgtitle [group_pattern]

xhdr header [range|MessageID]

xover [range]

xpat header range|MessageID pat [morepat...]

.

Для нашего протокола, сервер отвечает кодом 100, плюс сопроводительный текст.



Команда Lookup


Команда lookup принимает один или несколько почтовых кодов для поиска и возвращает название города и штат. Данные возвращаются в формате RFC откликов. Если код не найден, то отклик не возвращается (но если судить по примеру это не так, возвращает пустой отклик – строка с точкой). Код ответа "200 Ok".

Пример:

lookup 37642 16412

200 Ok

37642: CHURCH HILL, TN

16412: EDINBORO, PA

.

Даже если код не найден, то возвращается ответ "200 Ok".

lookup 99999

200 Ok

.

Мы приняли такое решение. Если бы сервер мог воспринимать только один параметр, то можно бы было отвечать кодом 200, и если не найден, то кодом 4XX. Но протокол может возвращать часть для правильных данных, поэтому было решено всегда возвращать код 200.

При частично правильных данных и ответ:

lookup 37642 99999

200 Ok

37642: CHURCH HILL, TN

.

Если бы протокол возвращал код ошибки, то частичные данные были бы проигнорированы. Данное решение позволило серверу отвечать и на частично правильные запросы, без генерации ошибки.



Команда Quit


Команда quit является прямым приказом серверу прекратить сессию и отсоединиться.

Посмотрим снова на сервер новостей Борланда. Его ответ следующий:

quit

205 closing connection - goodbye!

The postal code protocol responds similarly:

quit

201-Paka!      (Russians are everywhere J)

201 2 requests processed.

Почтовый протокол выдает многострочные ответы. Это не определено самим протоколом. Любые RFC ответы могут быть как однострочными, так и многострочными. Indy обрабатывает оба типа ответов автоматически.



Командные обработчики


Indy 9.0 содержит новое средство, называемое командные обработчики. Командные обработчики – это новая концепция, используемая в TIdTCPServer, которая позволяет серверу  выполнять парсинг команды и обрабатывать его для вас. Командные обработчики это разновидность «визуального управления сервером» и является только маленьким заглядыванием в будущие реализации Indy.

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

Вот маленький пример использования командных обработчиков. Во-первых вы должны определить две команды: QUIT и DATE. Создадим два командных обработчика, как указано ниже:

Для cmdhQuit свойство disconnect устанавливается в true. Для cmdhDate событие OnCommand определяется так:

procedure TForm1.IdTCPServer1cmdhDateCommand(ASender: TIdCommand);

begin

  ASender.Reply.Text.Text := DateTimeToStr(Date);

end;

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

Командные обработчики более подробно описаны в главе «командные обработчики».



Команды (commands)


Команда это текстовая строка, которая посылается клиентом серверу для запроса информации или выполнения определенных действий. Примеры команд: HELP, QUIT, LIST.

Команды могут содержать дополнительные параметры, разделенные пробелами.

Пример:

GET CHARTS.DAT

GET - это команда, а CHARTS.DAT – это параметр. В данном примере используется только один параметр, но команды могут содержать несколько параметров. Обычно параметры разделены пробелами, аналогично параметрам в DOS или в командной строке.

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

Один из плохих примеров последствий локализации команд, является Microsoft Office. Microsoft Office может быть автоматизирован, с помощью OLE. Тем не менее, Microsoft локализовал имена методов и свойств объектов. Это означает, что если вы пишите приложения с помощью Microsoft Office Automation в американской версии, то ваше приложение не будет работать во французской версии.



Компилятор DCCIL (Diesel)


DCCIL – это компилятор командной строки, который производит .NET вывод. DCCIL – это то, что было названо как "Delphi .NET preview compiler" и было включено в Delphi 7.

DCC – это имя стандартного компилятора командной строки в Delphi и это сокращение от Delphi Command line Compiler.

IL это ссылка на .NET Intermediate Language.

Отсюда DCC + IL = DCCIL. Произносить каждый раз D-C-C-I-L слишком громоздко и поэтому было применено имя "Diesel".

DCCIL имеет подобные DCC параметры и некоторые специфические для .NET расширения .



Компиляторы и среды (IDE)


Имеется несколько компиляторов и сред относящихся к Delphi и к .NET.



Компонент TIdAntiFreeze


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

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

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

Использование TIdAntiFreeze немного замедляет работу сокетов. Сколько давать приоритета приложению задается в свойствах TIdAntiFreeze. Причина, по которой TIdAntiFreeze замедляет сокетовые операции, состоит в том, что главному кодовому потоку разрешается обрабатывать сообщения. По этому надо позаботиться, чтобы не позволять много времени отводилось обработке сообщений. Это включает большинство таких событий, как OnClick, OnPaint, OnResize и многие другие. Поскольку неблокирующие сокеты тоже обмениваются сообщениями, этаже проблема относится и к ним. С Indy и с помощью использования TIdAntiFreeze, программист получает полный контроль.




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

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



Компонент TIdIOHandlerSocket


Компонент TIdIOHandlerSocket это обработчик IOHandler по умолчанию. Если обработчик не указан явно, то он создается неявно для вас. Компонент TIdIOHandlerSocket обрабатывает весь ввод/вывод, относящийся к TCP сокетам.

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