INDY IN DEPTH. ГЛУБИНЫ INDY
10. Реализация протоколов
В Indy реализовано большинство
распространенных протоколов. Но все равно бывают случаи, когда
требуется реализовать протокол самостоятельно. Основная причина
в необходимости реализации состоит в том, что нужный протокол
отсутствует.
Первый шаг в понимание что же надо
реализовать. Имеется три базовых типа протоколов:
1. Стандартный – эти протоколы относятся к Интернет стандартам.
Для понимания просто найдите в RFC нужный протокол. В RFC
протокол рассмотрен в подробностях.
2. Пользовательский – пользовательские протоколы используются,
когда отсутствует нужный протокол. Создание пользовательского
протокола будет описано позже.
3. Разработчика – это протоколы, предназначенные для общения с
собственными системами или оборудованием. Протоколы разработчика
– это пользовательский протокол, разработанный программистом, а
вы общаетесь с ним. Я желаю вам удачи, поскольку большинство
протоколов разработчика реализованы специалистами по
оборудованию, которые имели один курс обучения в колледже и не
имеют опыта разработки протоколов.
Большинство протоколов общаются, с помощью
текста, и если только у вас нет особых причин, то и вы тоже
должны поступать также.
Первым шагом построения клиента или
сервера – это понять протокол. Для стандартных протоколов это
может быть сделано с помощью чтения RFC. Для пользовательских
протоколов вы его должны сами разработать.
Большинство протоколов используют просто
текст. Общение означает посылку команд и получение ответов, а
возможно и данных. Текст делает протокол более простым для
отладки и позволяется использовать любые языки программирования
и операционные системы.
Код состояния традиционно трехзначный
номер. Не имеется стандарта на определение кодов состояния, но
многие протоколы используют де-факто следующие соглашения:
• 1xx - информационные
• 2xx - успешные
• 3xx – временные ошибки
• 4xx – постоянные ошибки
• 5xx – внутренние ошибки
Каждой ошибке обычно назначается
уникальный номер, но некоторые протоколы используют номера
повторно и только предоставляют уникальный цифровой номер для
каждой команды, а не протокола.
10.1. Терминология протокола
Перед обсуждением реализации протокола
рассмотрим некоторые термины.
10.1.1. Простой текст (plain text)
Простой текст (plain text) означает, что
все команды (commands) и ответы (replies) используют только
7-битный код ASCII. Если передача данных в откликах (responses)
допустима в двоичном виде, то почти все команды протокола и
ответы используют простой текст. Двоичный код никогда не должен
использоваться в командах и ответах, если на это не будет веских
оснований.
Использование простого текста упрощает
отладку и тестирование. Это также означает переносимость между
операционными системами и языками программирования.
10.1.2. Команды (commands)
Команда это текстовая строка, которая
посылается клиентом серверу для запроса информации или
выполнения определенных действий. Примеры команд: HELP, QUIT,
LIST.
Команды могут содержать дополнительные
параметры, разделенные пробелами.
Пример:
GET CHARTS.DAT
GET - это команда, а CHARTS.DAT – это
параметр. В данном примере используется только один параметр, но
команды могут содержать несколько параметров. Обычно параметры
разделены пробелами, аналогично параметрам в DOS или в командной
строке.
Команды всегда кодируются на английском
языке. Это может казаться предвзятым, тем не менее это общая
практика, как в техническом мире, так и в мире бизнеса. Если
английский не используется, то протокол не очень применим.
Один из плохих примеров последствий
локализации команд, является Microsoft Office. Microsoft Office
может быть автоматизирован, с помощью OLE. Тем не менее,
Microsoft локализовал имена методов и свойств объектов. Это
означает, что если вы пишите приложения с помощью Microsoft
Office Automation в американской версии, то ваше приложение не
будет работать во французской версии.
10.1.3. Ответы (reply)
Ответы – это короткий ответ на посланную
команду. Ответ содержит информацию о состоянии – успешно ли
ошибка, и иногда содержит небольшое количество данных.
Например, если команда GET customer.dat, вернет ответ 200 OK,
это будет означать, что команда воспринята и будет обработана.
Ответы обычно состоят только из одной строки, но могут состоять
и из нескольких строк.
В отличие от команд, текстовая часть
ответа может быть локализована на другой язык, если она
соответствует ограничению 7-бит ASCII. Поскольку протокол
использует цифровую часть, а текстовая часть используется только
для конечного пользователя и для отладки.
10.1.4. Отклики (response)
Отклик – это часть данных, которая
возвращается в ответ на команду. Отклики дополнительны и не
присутствуют во всех команда. Отклики посылаются после ответа,
для распознавание правильный ли ответ получен и какой формат
этого отклика.
Отклики могут быть текстовыми или
двоичными. Если отклик текстовый, то обычно этот отклик в
формате RFC откликов.
10.1.5 Переговоры (conversations)
Большинство протоколов аналогичны
переговорам. Некоторые очень просты, а некоторые нет, но обычно
они все равно в простом текстовом формате.
Переговоры означают следующую структуру:
1. отправка команды
2. возврат состояния
3. дополнительные данные отклика
Вернем обратно к примеру получения
почтовых кодов, в котором обмен выглядит следующим образом:
Client: lookup 37642 77056 Server: 200 Ok
Server: 37642: CHURCH HILL, TN Server: 77056: HOUSTON, TX Server:
.
Разделив на отдельные куски, разговор будет выглядеть так:
Команда:
Client: lookup 37642 77056 Ответ:
Server: 200 Ok Отклик:
Server: 37642: CHURCH HILL, TN Server: 77056: HOUSTON, TX Server:
.
Каждая из этих частей будет объяснена
ниже.
10.2 RFC - определения
В настоящем нет действующих стандартов для
терминов, обсуждаемых в данной главе. Тем не менее, эти термины
базируются на квази-стандартах, на которых работают все
тексто-ориентированые RFC протоколы.
Единственное значимое исключение- это
протокол POP3. Это мистерия, почему разработчики решили идти
своим путем, вместо пути RFC. Протокол POP3 в реальности очень
ограничен и не предлагает нужной дополнительной функциональности
к протоколу. Это обычная диверсия.
Протокол IMAP4, который был предложен как
наследник POP3, продолжил эту порочную практику и так же
использует не стандартный механизм. Протокол IMAP4 не получил
широкого распространения и POP3 остается стандартным протоколом
для почты.
После этих двух упоминаний, текстовый
протокол все еще остается квази-стандартным. Этот квази-стандарт
общий путь посылки команды и получение ответов и откликов.
10.2.1. RFC - коды состояния
Коды состояния RFC имеют следующую форму:
XXX Status Text Где XXX это цифровой код в диапазоне 100-599.
Трехзначный цифровой номер означает ответ,
который в ран-тайм, служит для определения результата выполнения
команды. Обычно присутствует дополнительный текст, показываемый
пользователю или для отладки. В этом случае, обычно используется
английский язык, но может быть и локализован, если будет
удовлетворять 7-битному коду ASCII. В некоторых случаях, когда
данные короткие, данные возвращаются в дополнительном текстовом
поле. В этих случаях данные все рано должны быть 7-бит ASCII, но
протокол сам определяет язык и ограничения форматов. В
большинстве случаев, эти данные языко-независимы (language
neutral). Например, команда "TIME", возвращает "15:30" в
дополнительном текстовом поле.
Пример RFC ответа: 404 No file exists
404 это цифровой отклик и "No file exists"
это дополнительное текстовое сообщение. Только код 404 должен
быть интерпретирован программой и код 404 должен быть точно
определен протоколом именно для этого. Текстовое сообщение
обычно используется для отладки, ведения логов или для показа
пользователю. Текстовое сообщение может иметь различные формы,
от реализации к реализации и может быть локализировано на другие
языки. Языки которые не соответствуют требованиям кода 7-бит
ASCII должны быть транслитерированы в английские символы.
Цифровая часть может быть назначена любым
значениям. Тем не менее существует общее соглашение:
• 1xx - информационные
• 2xx - успешные
• 3xx – временные ошибки
• 4xx – постоянные ошибки
• 5xx – внутренние ошибки
Числа обычно уникальные, но не всегда.
Если вы назначите 201 для "File not found", многие команды могут
отвечать этим кодом и значение всегда одно. В некоторых редких
случаях, значение числа зависит от примененной команды. В этом
случае, каждая команда назначает специфическое значение each
command assigns specific meanings to each numeric reply.
Цифровые коды, заканчивающие на 00, то
есть 100, 200, и так далее резервированы для общих ответов,
которые не имеют специального значения связанного с ними. 200
наиболее часто с "OК".
Коды состояния могут находиться на
нескольких строках и содержать большие текстовые сообщения. В
этом случае, остальные строки, за исключением последней должны
содержать код символа тире сразу после номера, вместо пробела.
Пример такого ответа:
400-Unknown Error in critical system
400-The server encountered an error and has no clue what caused
it. 400-Please contact Microsoft technical support, or your
local 400-tarot card reader who may be more helpful.
400 Thank you for using our products!
10.2.1.1. Примеры
Здесь пример некоторых кодов состояния, полученные от HTTP
протокола. Как вы видите они относятся к разным категориям по
первой цифре.
200 Ok
302 Redirect
404 Page not found
500 Internal Error
Если вы видите 500 Internal Error, велик шанс, что вы
используете Microsoft IIS. (Грубый наезд :-))
10.2.2. RFC – ответ (reply)
RFC ответ, возвращает код состояния.
10.2.3. RFC – отклик (response)
RFC отклик это текстовый ответ, ограниченный строкой с одной
точкой в начале. Если данные содержат строку, которая содержит
точку, то она перекодируется в две точки перед передачей, и
обратно преобразовываться в одну при приеме.
RFC отклики очень применимы, когда заранее неизвестно количество
возвращаемых данных. Это используется в HTTP, Mail, News и
других протоколах.
Методы Indy, которые поддерживают RFC отклики – это Capture (для
приема) и WriteStrings (для передачи).
10.2.4. RFC - транзакции
Транзакция RFC это общение, которое состоит из команды, ответа и
дополнительного отклика, все в формате RFC. Обработчики команд и
другие части Indy построены на транзакциях RFC.
Примет транзакции:
GET File.txt
201 File follows
Hello,
Thank you for your request, however we cannot grant your
request for funds for researching as you put it in your
application "A better mouse trap".
Thank you, and please do not give up.
10.3. Класс 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.
10.4. Класс 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. Это позволяет хранить
все тексты ответов в одном месте, позволяя легко управлять ими.
10.5. Курица или яйцо?
При построении системы, в которой вы должны построить, и сервер,
и клиента, возникает следующий вопрос - "что делать сначала,
клиента или сервера?". Оба нужны одновременно для отладки.
Ответ прост, проще построить сервер первым. Для тестирования
клиента, вы должны иметь сервер. Для тестирования сервера вам
нужен клиент. Но поскольку, протоколы как правило текстовые, то
клиент легко эмулировать с помощью телнета.
Для тестирования, подсоединитесь к серверу на его порт. В
командной строке введите: Telnet newsgroups.borland.com 119
Теперь нажмите клавишу enter. После соединения вы должны увидеть
экран, подобный нижнему рисунку.
На Windows 95/98/ME и NT это может выглядеть немного иначе, чем
на Windows 2000 или на Windows XP, но результат должен быть
таким же. Другие версии Windows загружают телнет,
как новое приложение в свом окне. Выше показанный рисунок
относится к Windows XP', в котором телнет является консольным
приложением.
Команда "Telnet newsgroups.borland.com 119" указывает клиенту
телнета, подсоединиться к newsgroups.borland.com на порт 119.
Порт 119 используется для протокола NNTP (News). Подобно
подсоединения к серверу новостей Borland, телнет может
использоваться для соединения с любым сервером, использующим
текстовый протокол.
Для отсоединения от сервера новостей введите команду "Quit" и
нажмите enter.
10.6. Определение пользовательского протокола
Задача сетевого разработчика состоит не только во взаимодействии
с существующими системами, но часто и в создании собственных. В
таком случае требуется создание своего протокола.
Первым шагом построения клиента или сервера – это разработка
протокола. Для стандартных протоколов, это решается изучением
соответствующего RFC. Если же протокол не стандартный, или уже
определен, то должен быть определен.
При определении протокола, должны быть сделаны следующие
решения:
• Текстовые или двоичные команды? Пока нет особых требований,
используйте текстовые команды. Текстовые команды проще для
понимания и для отладки.
• TCP или UDP? Это определяется от требований к протоколу.
Изучите все характеристики и решите с осторожностью. В
большинстве случаев TCP правильный выбор.
• Порт – каждому серверному приложению требуется выделенный порт
для прослушивания. Порты ниже 1024 резервированы и никогда не
должны использоваться, кроме реализации протокола, которому уже
назначен порт ниже 1024.
После определения команд, также должны быть определены ответы и
отклики.
10.7. Симуляция другой стороны (Peer Simulation)
Традиционно естественный путь построения клиента и сервера – это
сначала построение сервера, а затем клиента или построения их
параллельно. Но Indy имеет возможность построить клиент или
сервер, отдельно друг от друга. В некоторых случаях, один может
быть построен без необходимости доступа к другому. В таких
случаях может использоваться эмуляция (видимо симуляция, судя по
названию главы) другой стороны.
Эмуляция другой стороны будет
обсуждена позже в главе 14. Отладка.
10.8. Протокол получения почтового кода
В данной главе более подробно обсуждается Протокол получения
почтового кода, который был представлен ранее в его клиенте. Сам
сервер будет обсужден позже.
Проект был разработан так, чтобы быть как можно более простым.
Сервер получения почтового кода (Zip код в Америке) позволяет
клиенту запросить город и штат, к которому относится почтовый
код.
Примерные данные, которые использует сервер, относятся к
американским почтовым кодам, которые у них называются zip коды.
Протокол может обрабатывать и другие коды, но американские коды
уже заложены в демо программу.
Для тех, кто находится за пределами Соединенных Штатов Америки и
не знаком с их системой, zip это почтовый код в США, который
указывает регион доставки. Zip коды цифровые и состоят из 5
цифр. Zip коды могут также содержать дополнительные четыре цифры
в формате 16412-0312. Данный тип кодов получил название Zip+4.
Четыре дополнительные цифры уточняют локальную зону доставки и
не требуются для определения города.
При создании протокола были приняты следующие решения:
• Все команды текстовые
• Транспорт TCP
• Порты: 6000. Порт 6000 это наиболее часто используемый номер в
тестовых примерах Indy. Это не имеет значения.
Протокол поддерживает следующие команды
• Help – получение справки
• Lookup <почтовый код 1> < почтовый код 2> ... – запрос
информации
• Quit – отсоединение от сервера
При разработке протокола, полезно знать ключевые протоколы,
такие как - NNTP, SMTP и HTTP и использовать их как модель.
Исключая POP3 и IMAP4. Поскольку это плохой пример построения
протоколов.
Поскольку NNTP поддерживает передачу и прием сообщений в рамках
одно протокола, Протокол NNTP будет упоминаться в данной книге
несколько раз.
10.8.1. Команда Help
Команда Help очень часто используемая команда и редко
применяемая в автоматических клиентах. Данная команда наиболее
пригодна для использования человеком, который или тестирует, или
напрямую работает с сервером. Почти все серверы реализуют данную
команду.
Команда Help полезна для вывода справки о командах сервера и их
возможном применении.
Вот пример ответа Борландовского сервера новостей сервера, на
команду HELP:
Для нашего протокола, сервер отвечает кодом 100, плюс
сопроводительный текст.
10.8.2. Команда 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
Если бы протокол возвращал код ошибки, то частичные данные были
бы проигнорированы. Данное решение позволило серверу отвечать и
на частично правильные запросы, без генерации ошибки.
10.8.3. Команда Quit
Команда quit является прямым приказом серверу прекратить сессию
и отсоединиться.
Посмотрим снова на сервер новостей Борланда. Его ответ
следующий:
quit
205 closing connection - goodbye!
The postal code protocol responds similarly:
quit
201-Paka! (Russians are everywhere ☺)
201 2 requests processed.
Почтовый протокол выдает многострочные ответы. Это не определено
самим протоколом. Любые RFC ответы могут быть как однострочными,
так и многострочными. Indy обрабатывает оба типа ответов
автоматически.
|