Глубины Indy. 2. Техническая поддержка
Скачать 1.03 Mb.
|
procedure TformMain.IdTCPServer1Execute(AThread: TIdPeerThread); var LCmd: string ; begin with AThread.Connection do begin LCmd := Trim(ReadLn); if SameText(LCmd, 'QUIT' ) then begin WriteLn( '200 Good bye' ); Disconnect; end else if SameText(LCmd, 'DATE' ) then begin WriteLn( '200 ' + DateToStr(Date)); end else begin WriteLn( '400 Unknown command' ); end ; end ; end ; здесь нет необходимости проверять действительность соединения, так как Indy делает это автоматически. Так же нет необходимости производить опрос, поскольку и это Indy делает автоматически за вас. Она вызывает событие периодически, пока соединение не прекратится. Это может быть вызвано или явным отсоединением, или по сетевой ошибке, или если клиент отсоединился. В действительности, не требуется делать никаких опросов на предмет отсоединений. Если данный опрос все же необходимо делать, вам надо только позаботиться об возбуждении исключений, что бы Indy смог нормально их отработать. 17.1.1.5. Командные обработчики 81 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 ; это законченный код командного обработчика. Все другие детали, специфицированы установкой свойств в командных обработчиках. Командные обработчики более подробно описаны в главе «командные обработчики». 17.1.2. Класс TIdUDPServer Поскольку UDP не требуется соединения (по определению), то класс TIdUDPServer работает отлично от TIdTCPServer. Подобно TIdSimpleServer класс TIdUDPServer не имеет некоторых режимов, и поскольку UDP не требуется соединения, TIdUDPClient имеет только слушающие методы. При активизации, класс TIdUDPServer создает слушающий поток, для прослушивания входящих UDP пакетов. Для каждого, принятого UDP пакета, класс TIdUDPServer возбуждает событие OnUDPRead в главном потоке или в контексте слушающего потока, в зависимости от значения свойства ThreadedEvent. Когда значение свойства ThreadedEvent = false, то событие OnUDPRead возбуждается в контексте главного потока программы. Когда значение свойства ThreadedEvent = true, то событие OnUDPRead возбуждается в контексте слушающего потока. 82 Когда значение свойства ThreadedEvent равно false, то блокируется прием дальнейших сообщений. Поэтому событие OnUDPRead должно быть как можно более быстрым. 17.1.3. Класс TIdSimpleServer Класс TIdSimpleServer предназначен для разового использования серверов. Класс TIdSimpleServer предназначен для обслуживания одного соединения за раз. Хотя он может обслуживать другие запросы по окончанию, обычно он используется только для одного запроса. Класс TIdSimpleServer не создает потоков для прослушивания или вторичных потоков соединения. Вся функциональность реализована в одном потоке. Компонент клиента TIdFTP использует класс TIdSimpleServer. Когда FTP выполняет передачу, вторичное TCP соединение открывается для передачи данных и закрывается, когда данные будут переданы. Данное соединение называется «канал данных (data channel)» и оно уникально для каждого передаваемого файла. 17.2. События потоков События TIdTCPServer потоковые. Это означает, что они не являются частью потока, они выполняются внутри потока. Это очень важная деталь. Будьте уверены, что вы понимаете эту деталь до начала обработки. Это сначала может показаться странным, что событие может быть частью формы но при этом выполняться внутри потока. Тем не менее, это было умышленно так сконструировано, чтобы события созданные в дизайн тайм, были подобны любым другим событиям, без необходимости создания пользовательского класса и перекрытия метода. В создаваемых компонентах наследниках, перекрытие тоже доступно. Но для построения приложений, модель обработчиков событий намного проще в применении. Каждый клиент создает свой собственный поток. При использовании данного потока, события TCP сервера (который является частью формы или модуля данных) вызываются из данных потоков. Это означает, что одиночное событие может быть вызвано множество раз из разных потоков. Такие события получают в качестве аргумента AThread, который указывает на поток из которого возбуждено событие. 83 Примерами потоковых события являются командные обработчики сервера OnConnect, OnExecute и OnDisconnect. 17.3. Модели TCP серверов TCP сервер Indy поддерживает две модели для построения серверов. Данные методы это OnExecute и командные обработчики. Indy 8 поддерживает только OnExecute. 17.3.1 Событие OnExecute Событие OnExecute ссылается на событие OnExecute класса TIdTCPServer. При реализации сервера по данной модели, должно быть определено событие OnExecute или перекрыт метод DoExecute. Модель OnExecute допускает полный контроль разработчиком и позволяет реализовывать любые типы протоколов, включая двоичные протоколы. После подсоединения клиента к серверу, возбуждается событие OnExecute. Если событие OnExecute не определено, то возбуждается исключение. Событие OnExecute возбуждается в цикле, как только подсоединяется клиент. Это очень важная деталь и поэтому разработчик должен побеспокоиться об 1. Помнить о том, что событие возникает в цикле. 2. Не препядствовать Indy выполянть обработку в цикле. Внутренний цикл показан на следующей диаграмме: На этапе проверки соединения выполняется следующие проверки: Клиент еще подсоединен Disconnect не был вызван во время OnExecute Отсутствуют фатальные ошибки Не было возбуждено необработанное исключение в OnExecute Сервер еще активен 84 Если все эти проверки и другие проверки истинны, то событие OnExecute возбуждается снова. Поэтому, разработчик никогда не должен конструировать свой цикл внутри OnExecute, который будет дублировать это, так как это будет мешать Indy. 17.3.2. Обработчики команд (Command Handlers) Командные обработчики подобны спискам действий для построения серверов, в стиле визуальной среды проектирования. Командные обработчики ограничены текстовыми протоколами. Данные, передаваемые по протоколу, могут быть двоичными. Обработчики команд автоматически читают и разбирают команды. При этом возбуждается специфическое событие OnCommand. 17.4. Обработчики команд (Command Handlers) Создание серверов в Indy всегда было достаточно простой задачей, тем не менее в Indy 9 это стало проще после введения командных обработчиков в класс TCP сервера (TIdTCPServer). Обработчики команд подобны спискам действий для сервера. Командные обработчики работают следующим образом: - вы создаете обработчик команд для каждой команды и затем используя обработчик команд определяете поведение для конкретной команды. Когда команда принята от клиента, то сервер автоматически разбирает ее и передает конкретному обработчику. Обработчики команд не только имеют свойства для настройки поведения, но также методы и события. Обработчики команд работают только с текстовыми командами и ответами TCP протоколов. Тем не менее это покрывает нужды почти 95% серверов используемых в настоящее время. Хотя обработчик в состоянии работать с двоичными данным, но сами 85 команды могут быть только текстовыми. Имеется некоторое количество протоколов, которые работают с помощью двоичных команд. Для протоколов, использующих двоичные команды или текстовые команды, которые не совместимы (от корректора: труднореализуемые??? Не могу себе представить что он имел в виду, потому что conversational это словоохотливый, разговорчивый), реализация обработчиков команд не является обязательной что позволяет сохранить обратную совместимость. 17.4.1. Реализация Класс TCPServer содержит свойство, именуемое CommandHandlers, которое является коллекцией обработчиков команд. Обработчики обычно создаются во время разработки, тем не менее, при реализации наследников они могут создаваться и во время исполнения. Если командные обработчики создаются во время исполнения, то они должны быть созданы путем перекрытия метода InitializeCommandHandlers. Это гарантирует, что они создадутся только во время исполнения. Если они создаются в конструкторе, они будут создаваться каждый раз, когда TCPServer загружается из потока и записывается обратно в поток. Это может привести к созданию множества копий для каждого обработчика. Инициализация, напротив, вызывается только однажды после первой активации TCPServer. Класс TCPServer содержит несколько свойств и событий имеющих отношение к обработчикам команд. Свойство CommandHandlersEnabled разрешает или запрещает работу обработчика как единого целого. Свойство OnAfterCommandHandler возбуждается после выполнения каждого обработчика и событие OnBeforeCommand возбуждается перед выполнением каждого обработчика. Событие OnNoCommandHandler возбуждается если обработчик, соответствующий команде, не найден. Если свойство CommandHandlersEnabled равно true и определены обработчики, то выполняется их обработка. Иначе вызывается событие OnExecute, если оно назначено. Обработчик OnExecute не вызывается если были обработаны команды. Если есть соединение, TCPServer читает строки текста из соединения и пытается найти подходящий обработчик команд. Любые пустые строки игнорируются. Для непустых строк сначала возбуждается событие OnBeforeCommandHandler. Затем ищется подходящий командный обработчик. Если командный обработчик найден и его свойство enabled установлено в true, то возбуждается его событие OnCommand, а иначе возбуждается событие OnNoCommandHandler. После всего этого возбуждается событие OnAfterCommand. 17.4.2. Пример протокола Для демонстрации базовой реализации обработчиков команд, определим простой протокол. Для демонстрации пользовательского сервера времени реализуем три команды: Help – показывает список поддерживаемых команд и их форматы. DateTime Quit – закрывает сессию и отсоединяется. Это очень простая базовая реализация, но она работает вполне приемлемо для целей демонстрации. Конечно, вы можете ее расширить для того чтобы изучить возможности обработчиков команд. 86 17.4.3. Базовый пример Сначала сконструируем базу для построения примера. Это подразумевает, что вы уже умеете работать с TIdTCPServer и вот ваши следующие шаги. Для построения базового примера выполним следующие шаги: 1. Создадим новое приложение. 2. Добавим TIdTCPServer на форму. 3. Установим свойство TIdTCPServer.Default в 6000. порт 6000 это порт для демо, выбранный случайным образом, можно использовать любой свободный порт. 4. Установим свойство TIdTCPServer.Active в True. Это должно активировать сервер при старте приложения. Этим мы создали базовое приложение. Оно пока ничего не делает, поскольку еще нет ни обработчиков команд, ни событий. 17.4.4. Создание обработчика команд Обработчики команд создаются при редактировании свойства CommandHandlers класса TIdTCPServer. Свойство CommandHandlers – это коллекция. Обработчики могут быть модифицированы как во время исполнения, так и во время разработки. Для редактирования обработчиков во время разработки нажмите на кнопку <...> на свойстве CommandHandlers в инспекторе объектов. Появится следующий диалог: Он пока пуст, поскольку еще нет ни одного обработчика. Для создания обработчика команд, или нажмите правую кнопку мыши и выберите пункт Add, или нажмите первую кнопку в панели инструментов диалога. После это в списке появится обработчик команд. 87 Для редактирования обработчика выберите его в инспекторе объектов. Редактирование обработчиков подобно редактированию полей набора данных БД или колонок в DBGrid. Если инспектор объектов не виден, то нажмите F11 для его отображения. Инспектор объектов выглядит как на приведенном рисунке. Показано, что есть уже одно измененное свойство, реализующее команду. Это команда QUIT и она будет обсуждена ниже. Пошаговое описание реализации команды QUIT: 1. Command = Quit – это команда сервера которую сервер будет использовать для поиска обработчика при чтении ввода. Команда не чувствительна к регистру. 2. Disconnect = True – это значит, что сервер отсоединится от клиента после получении и обработки данной команды. 3. Name = cmdhQuit – данное свойство не оказывает никакого влияния на обработку, но оно предназначено для упрощения идентификации обработчика в коде. Данный шаг необязательный. 4. ReplyNormal.NumericCode = 200 – Команды обычно возвращают 3-х разрядный код и необязательный текст. Задав это свойство, мы указывем обработчику возвращать в ответ на команду код 200 и дополнительный текст из ReplyNormal.Text если конечно не произойдет ошибка во время выполнения команды. 5. ReplyNormal.Text = Good Bye – дополнительный текст, который посылается вместе с ReplyNormal.NumericCode. После этого мы имеем полностью работоспособный обработчик команд. 17.4.5. Поддержка обработчика команд Теперь когда обработчик создан, есть еще несколько глобальных параметров, относящихся к северам на текстовых командах серверов и обработчиков команд, которые также должны быть установлены. Все это свойства TIdTCPServer, а не обработчикам команд. 88 17.4.5.1. Свойство Greeting (приветствие) Обычной практикой для серверов, является предоставления информации, приветствия от сервера, перед тем как сервер начнет обрабатывать команды клиента. Типичный ответ сервера, показывающий, что сервер готов, это код 200 и установка кода не равным нулю, разрешит посылку приветствия Установите свойства Greeting. NumericCode = 200 и Greeting.Text в "Hello". 17.4.5.2. Свойство ReplyExceptionCode Если во время обработки команд обнаружатся не обслуженные исключения, то используется данное свойство со значением отличным от нуля. Код 500 это типичный ответ для внутренних, неизвестных ошибок. Вместе с кодом отсылается и текстовый отзыв. Установите ReplyExceptionCode в 500. 17.4.5.3. Свойство ReplyUnknownCommand Если во время обработки команд обнаружатся не обработанные исключения, то данное свойство будет использовано для построения ответа, если его значение отличается от нуля. Код 400 наиболее общий ответ для подобных случаев. Установите ReplyUnknown.NumericCode в 400 и ReplyUnknown.Text в "Unknown Command". 17.4.5.4. Прочие свойства У TIdTCPServer есть еще и другие свойства и события, для реализации дополнительного поведения, относящего к командным обработчикам, но приведенные выше являются минимумом, который должен быть реализован. 17.4.6. Тестирование новой команды Теперь, когда команда уже реализована можно приступить и к тестированию, просто воспользуемся Telnet, поскольку протокол текстовый: 1. Запустим приложение. 2. В меню Start: Run введем: telnet 127.0.0.1 6000 и нажмем OK. Это указывает Telnet подсоединиться к компьютеру на порт 6000, который используется в демонстрационном примере. 3. Сервер должен ответить 200 Hello, что является приветствием, из свойства Greeting of TIdTCPServer. 4. Telnet затем покажет каретку. Это означает, что сервер готов и ожидает команду. 5. Введем HELP и нажмем enter. Сервер ответит "400 Unknown Command". Поскольку пока мы не создали командного обработчика для команды HELP и ответ "400 Unknown Command" был взят из свойства ReplyUnknown. 6. Введем QUIT. Сервер ответит "200 Good Bye" и отсоединится от клиента. 89 Поздравляем! Вы построили сервер с обработчиком команд. В следующей главе мы реализуем остальные две команды - HELP и DATETIME, которые имеют отличное от команды QUIT поведение. 17.4.7. Реализация HELP Команда HELP подобно по поведению на команду QUIT за исключением двух различий. 1. Не происходит разъединение сеанса. 2. В дополнение ответ также предоставляет текстовый отклик со справочной информацией. Для реализации команды HELP выполним следующие шаги: 1. Создадим новый командный обработчик. 2. Command = Help 3. Name = cmdhHelp 4. ReplyNormal.NumericCode = 200 5. ReplyNormal.Text = Help Follows Все эти шаги знакомы вам по реализации команды QUIT. Дополнительное свойство, которое здесь используется - это свойство Response, которое является списком строк. Если свойство Response содержит текст, то оно посылается клиенту после отсылки ReplyNormal. Для реализации команды HELP используется редактор строк свойства Response: Help - Display a list of supported commands and basic help on each. DateTime format. If no format is specified the format yyyy-mm-dd hh:nn:ss will be used. Quit - Terminate the session and disconnect. Теперь если вы подсоединитесь к серверу и пошлете команду HELP, то сервер ответит следующим образом: 200 Hello help 200 Help Follows Help - Display a list of supported commands and basic help on each. DateTime format. If no format is specified the format yyyy-mm-dd hh:nn:ss will be used. Quit - Terminate the session and disconnect. . |