Настоящее издание относится к:
а также ко всем последующим выпускам и модификациям, если в последующих изданиях не будет оговорено противное.
Для заказа публикаций обратитесь в местное представительство или филиал IBM.
В этом разделе описываются цели, структура и условные обозначения, используемые в документе WebSphere Application Server Programming Guide for Edge Components.
В этой книге описываются прикладные программные интерфейсы (API), доступные для настройки продукта Edge components сервера WebSphere Application Server версии 6.1. Эти сведения предназначены для разработчиков программных модулей. Эта информация также может заинтересовать проектировщиков сетей и системных администраторов, которые могут найти здесь описание возможностей по настройке данного продукта.
Для понимания информации, приведенной в данной книге, необходимо иметь представление о приемах программирования на языках Java или C, в зависимости от используемого API. Методы и структуры для каждого из этих интерфейсов описаны в соответствующей документации, но вы должны уметь создавать собственные приложения, а также компилировать и тестировать их. Для некоторых интерфейсов приводятся примеры программ, однако их можно использовать только как руководство для создания собственных приложений.
В этой документации используются следующие обозначения.
Обозначение | Значение |
---|---|
Полужирное начертание | Относится к меню, элементам меню, меткам, кнопкам, значкам и папкам графического интерфейса пользователя (GUI). Также применяется для выделения названий команд в обычном тексте. |
Интервал | Обозначает текст, который необходимо ввести в командной строке. Также применяется для обозначения текста на экране, примеров программ и частей файлов. |
Курсив | Применяется для обозначения значений переменных (например, вместо переменной ИмяФайла необходимо указать имя файла). Также используется в заголовках книг, для выделения текста и пр. |
Ctrl-x | Где x - это название клавиши или комбинация клавиш. Например, Ctrl-c означает нажать клавишу C, удерживая нажатой клавишу Ctrl. |
Return | Применяется для обозначения клавиш Return, Enter или левой стрелки. |
% | Обозначает командную строку в операционных системах Linux и UNIX, для использования которой полномочия пользователя root не требуются. |
# | Обозначает командную строку в операционных системах Linux и UNIX, для использования которой требуются полномочия пользователя root. |
C:\ | Обозначает командную строку Windows. |
Ввод команд | Если указано "ввести" или "выполнить" команду, введите команду и нажмите клавишу Return. Например, инструкция "Введите команду ls" означает, что в командной строке необходимо ввести ls и нажать клавишу Return. |
[ ] | Обозначает необязательные параметры в синтаксисе команды. |
{ } | Обозначает списки для выбора параметров команды. |
| | Отделяет допустимые значения параметров, заключенных в { } (скобки) в синтаксисе команды. |
... | Многоточие в синтаксисе команды означает, что предыдущий элемент можно ввести еще несколько раз. В примерах программ многоточие означает опущенный для краткости исходный код. |
Специальные функции доступа позволяют работать с программой людям с ограниченными физическими возможностями, например, с ограниченной подвижностью или со сниженным зрением. В WebSphere Application Server версии 6.1 предусмотрены следующие специальные функции доступа:
Ваши отзывы помогают нам обеспечивать высокое качество и точность публикуемой информации. Если у вас есть комментарии по этой книге или другой документации для Edge components сервера WebSphere Application Server:
В этой книге обсуждаются прикладные программные интерфейсы (API), предоставляемые для продукта Edge components сервера WebSphere Application Server. (Продукт Edge components для сервера WebSphere Application Server включает компоненты Caching Proxy и Load Balancer.) Для настройки взаимодействия между Edge components, а также с другими системами администраторы могут использовать различные интерфейсы.
ВАЖНЫЕ ИСКЛЮЧЕНИЯ:
API, описанные в этом документе, относятся к нескольким категориям.
Компонент Caching Proxy включает несколько интерфейсов, записанных в последовательность обработки, в которую можно добавлять пользовательские функции или использовать вместо стандартной обработки. Настройка включает изменение или расширение следующих задач:
Пользовательские приложения (или модули Caching Proxy) вызываются в определенные моменты последовательности обработки сервера Proxy.
API компонента Caching Proxy применяется для реализации определенных функций системы. Например, поддержка LDAP реализована в виде модуля.
API Caching Proxy подробно описывает интерфейс и содержит инструкции по настройке сервера Proxy для работы с модулями.
Для настройки компонента Load Balancer используются пользовательские советники. Советники измеряются фактическое значение нагрузки на серверах. Пользовательские советники позволяют использовать собственные методы измерения нагрузки в конкретной системе. Эта функция особенно для полезна для измененных или специализированных Web-серверов.
Пользовательские советники содержит подробную информацию о разработке и использовании пользовательских советников. Также содержит примеры программ советников.
Примеры программы для этих API можно найти на компакт-диске Edge Components в каталоге samples. Дополнительные примеры программы доступны на Web-сайте WebSphere Application Server, www.ibm.com/software/webservers/appserv/
В этом разделе рассказано об интерфейсах прикладного программирования (API) Caching Proxy, т.е. о том, что это такое, зачем оно нужно и как работает.
ВАЖНАЯ ИНФОРМАЦИЯ: Caching Proxy может присутствовать во всех устанавливаемых конфигурациях Edge Components, за исключением следующих случаев:
API - это интерфейс Caching Proxy, позволяющий вам расширять базовые возможности сервера Proxy. Вы можете создавать расширения или встраиваемые модули для реализации настраиваемых алгоритмов работы. Вот некоторые примеры применения API:
API Caching Proxy предоставляет следующие преимущества:
Перед написанием собственных программ модулей Caching Proxy необходимо ознакомиться с принципом работы сервера proxy. Работу сервера proxy при обработке запросов можно набить на несколько отдельных этапов. Для каждого из этих этапов вы можете указать с помощью API собственные функции. Например, хотите ли выполнить какие-либо действия после считывания клиентского запроса, но перед выполнением каких-либо других операций? Или, может быть, вам требуется выполнить какие-либо особые процедуры во время идентификации и повторить их после отправки запрошенного файла?
API предоставляют библиотеку заранее определенных функций. Ваши программы модулей могут вызывать библиотечные функции API для взаимодействия с процессами сервера proxy (например, для манипуляций с запросами, считывания и записи заголовков запросов, либо для занесения записей в протоколы сервера proxy). Эти библиотечные функции не следует путать с вашими собственными функциями модулей, вызываемыми сервером proxy. Заранее определенные функции описаны в разделе Заранее определенные функции и макросы.
Указать серверу proxy, какие из ваших функций модулей должны вызываться на каждом из этапов обработки, можно с помощью директив API Caching Proxy, заданных в файле конфигурации сервера. Эти директивы описаны в разделе Директивы конфигурации Caching Proxy для этапов обработки API.
В настоящий документ включены следующие сведения:
С помощью этих компонентов и процедур вы сможете создавать собственные программы модулей Caching Proxy.
Работу сервера proxy можно разделить на несколько этапов в соответствии с типом обработки, выполняемой на каждом из этих этапов. Каждый этап включает промежуточную точку, на которой может быть выполнена указанная часть вашей программы. Добавляя в файл конфигурации Caching Proxy (ibmproxy.conf) директивы API, вы указываете, какие функции модуля должны вызываться на каждом этапе. Указав для одного этапа несколько директив, вы можете вызывать для этого этапа несколько функций модуля.
Некоторые этапы входят в состав процесса обработки запроса сервером. Другими словами, сервер proxy выполняет эти этапы каждый раз, когда он обрабатывает полученный запрос. Другие этапы выполняются независимо от обработки запросов, т.е. сервер выполняет их независимо от того, выполняется какой-либо запрос или нет.
Ваши откомпилированные программы хранятся в общем объекте, например в файле DLL или .so, в зависимости от операционной системы. По мере выполнения этапов обработки запроса сервер вызывает связанные с каждым этапом функции модулей до тех пор, пока одна из функций не укажет, что она обработала запрос. Если вы указали для какого-либо этапа несколько функций модулей, то эти функции вызываются в том порядке, в котором соответствующие директивы указаны в файле конфигурации.
Если запрос не обрабатывается функцией модуля (из-за того, что вы не включили директиву API Caching Proxy для соответствующего этапа или функция модуля для этого этапа вернула значение HTTP_NOACTION), то сервер выполняет действие по умолчанию для этого шага.
Примечание: Это верно для всех этапов, за исключением этапа Service, для которого не предусмотрено действие по умолчанию.
Рис. 1 иллюстрирует этапы обработки сервера proxy и определяет последовательность выполнения этапов, связанных с обработкой запросов.
Четыре из показанных на диаграмме этапов выполняются независимо от обработки запросов клиентов. Эти этапы связаны с работой и обслуживанием сервера proxy. К их числу относятся:
В следующем списке разъясняется назначение каждого этапа, изображенного на Рис. 1. Обратите внимание, что не все этапы обязательно выполняются при обработке каждого запроса.
Выполняется после чтения запроса, но перед любыми другими действиями.
Если по завершении обработки этот этап указывает, что запрос обработан (HTTP_OK), то сервер пропускает остальные этапы обработки запроса и выполняет только этапы Transmogrifier, Log и PostExit.
Использует сохраненные маркеры системы безопасности для проверки доступа к физическим каталогам, ACL, других средств управления доступом, а также для формирования заголовков WWW-Authenticate, необходимых для проведения базовой идентификации. Если вы создаете собственную функцию модуля, замещающую этот этап, то вы должны самостоятельно сформировать эти заголовки.
Дополнительная информация приведена в разделе Идентификация и проверка прав доступа.
Декодирует, проверяет и сохраняет маркеры системы безопасности.
Дополнительная информация приведена в разделе Идентификация и проверка прав доступа.
Выполняется после проверки прав доступа и обнаружения объекта, но перед собственно выполнением запроса.
Если по завершении обработки этот этап указывает, что запрос обработан (HTTP_OK), то сервер пропускает остальные этапы обработки запроса и выполняет только этапы Transmogrifier, Log и PostExit.
В системах AIX вам потребуется файл экспорта (например, libmyapp.exp), в котором перечислены функции модуля. Кроме того, необходимо будет выполнить связывание с файлом импорта API Caching Proxy libhttpdapi.exp.
В системах Linux, HP-UX и Solaris необходимо выполнить связывание с библиотеками libhttpdapi и libc.
В системах Windows вам потребуется файл определения модуля (.def), в котором перечислены функции модуля. Кроме того, необходимо будет выполнить связывание с файлом HTTPDAPI.LIB.
Обязательно включите в определения функций файл HTAPI.h и используйте макрос HTTPD_LINKAGE. Этот макрос обеспечивает единый способ вызова всех функций.
В качестве руководства используйте следующие команды компиляции и связывания.
cc_r -c -qdbxextra -qcpluscmt foo.c
cc_r -bM:SRE -bnoentry -o libfoo.so foo.o -bI:libhttpdapi.exp -bE:foo.exp
(Эта команда показана на двух строках лишь для более удобного чтения.)
cc -Ae -c +Z +DAportable
aCC +Z -mt -c +DAportable
gcc -c foo.c
ld -G -Bsymbolic -o libfoo.so foo.o -lhttpdapi -lc
cc -mt -Bsymbolic -c foo.c
cc -mt -Bsymbolic -G -o libfoo.so foo.o -lhttpdapi -lc
cl /c /MD /DWIN32 foo.c
link httpdapi.lib foo.obj /def:foo.def /out:foo.dll /dll
Для создания списка экспорта воспользуйтесь одним из следующих методов:
При написании собственных функций для вызова на различных этапах обработки запросов следуйте синтаксическим диаграммам, показанным в Прототипы функций модулей.
Каждая функция должна указывать в параметре кода возврата значение, указывающее на выполненное действие:
В описании прототипов функций для каждого этапа обработки Caching Proxy указаны применяемые форматы и рассказано о выполняемых операциях. Обратите внимание, что имена функций не заданы заранее. Вы должны присвоить своим функциям уникальные имена, причем можете следовать собственному соглашению о присвоении имен. Для простоты в этом документе применяются имена, соответствующие этапам обработки.
В каждой из функций модуля допустимы определенные библиотечные функции API. Некоторые функции допустимы не на всех этапах. Следующие библиотечные функции API можно вызывать их всех функций модулей:
Дополнительные допустимые и недопустимые функции API перечислены в описаниях прототипов функций.
Значение переданного вашей функции параметра handle можно передать в виде первого аргумента библиотечной функции. Библиотечные функции API описаны в разделе Заранее определенные функции и макросы.
void HTTPD_LINKAGE ServerInitFunction ( unsigned char *handle, unsigned long *major_version, unsigned long *minor_version, long *return_code )
Определенная для этого этапа функция вызывается один раз во время загрузки модуля при инициализации сервера. В этот момент вы можете выполнить собственные действия по инициализации перед началом обработки запросов.
Несмотря на то, что должны вызываться все функции инициализации сервера, возврат кода ошибки функцией на этом этапе приводит к тому, что все остальные функции, настроенные в том же модуле, что и функция, вернувшая код ошибки, игнорируются. (Это значит, что все функции, находящиеся в том же общем объекте, что и функция, вернувшая код ошибки, не вызываются.)
Параметр version содержит номер версии сервера proxy. Он передается сервером Caching Proxy.
void HTTPD_LINKAGE PreExitFunction ( unsigned char *handle, long *return_code )
Определенная для этого этапа функция вызывается для каждого запроса после его считывания, но перед выполнением каких-либо других действий по обработке этого запроса. На этом этапе модуль может обращаться к клиентскому запросу до его обработки Caching Proxy.
Допустимые коды возврата для функции preExit:
Другие коды возврата использовать нельзя.
Если функция возвращает результат HTTP_OK, то сервер proxy считает, что запрос обработан. Все последующие этапы обработки запроса в этом случае пропускаются и выполняются только этапы отправки ответа (Transmogrifier, Log и PostExit).
На этом этапе допустимы все библиотечные функции сервера.
void HTTPD_LINKAGE MidnightFunction ( unsigned char *handle, long *return_code )
Определенная для этого этапа функция вызывается один раз в сутки, в полночь. Она не связана с контекстом запросов. Например, она может применяться для вызова дочернего процесса и анализа протоколов. (Обратите внимание, что высокая нагрузка на этом этапе может помешать нормальному ведению протоколов.)
void HTTPD_LINKAGE AuthenticationFunction ( unsigned char *handle, long *return_code )
Определенная для этого этапа функция вызывается для каждого запроса в соответствии со схемой идентификации запроса. Эта функция может применяться для настройки процедур проверки маркеров защиты, отправленных вместе с запросом.
void HTTPD_LINKAGE NameTransFunction ( unsigned char *handle, long *return_code )
Определенная для этого этапа функция вызывается для каждого запроса. Если вы хотите, чтобы функция модуля вызывалась только для запросов, соответствующих определенному шаблону, то необходимо указать такой шаблон URL в директиве файла конфигурации. Этап преобразования имен NameTrans выполняется перед началом обработки запроса и обеспечивает механизм установления соответствия между URL и объектами файловой системы, например, именами файлов.
void HTTPD_LINKAGE AuthorizationFunction ( unsigned char *handle, long *return_code )
Определенная для этого этапа функция вызывается для каждого запроса. Если вы хотите, чтобы функция модуля вызывалась только для запросов, соответствующих определенному шаблону, то необходимо указать такой шаблон URL в директиве файла конфигурации. Этап проверки прав доступа (Authorization) выполняется перед началом обработки запроса и может применяться для проверки допустимости возврата найденного объекта клиенту. При использовании базовой идентификации необходимо сформировать обязательные заголовки WWW-Authenticate.
void HTTPD_LINKAGE ObjTypeFunction ( unsigned char *handle, long *return_code )
Определенная для этого этапа функция вызывается для каждого запроса. Если вы хотите, чтобы функция модуля вызывалась только для запросов, соответствующих определенному шаблону, то необходимо указать такой шаблон URL в директиве файла конфигурации. Этап определения типа объекта (ObjectType) выполняется перед началом обработки запроса. Он применяется для проверки наличия объекта и определения его типа.
void HTTPD_LINKAGE PostAuthFunction ( unsigned char *handle, long *return_code )
Определенная для этого этапа функция вызывается после проверки прав доступа, но перед выполнением каких-либо других действий. Если функция возвращает результат HTTP_OK, то сервер proxy считает, что запрос обработан. Все последующие этапы обработки запроса в этом случае пропускаются и выполняются только этапы отправки ответа (Transmogrifier, Log и PostExit).
На этом этапе допустимы все библиотечные функции сервера.
void HTTPD_LINKAGE ServiceFunction ( unsigned char *handle, long *return_code )
Определенная для этого этапа функция вызывается для каждого запроса. Если вы хотите, чтобы функция модуля вызывалась только для запросов, соответствующих определенному шаблону, то необходимо указать такой шаблон URL в директиве файла конфигурации. Этап обслуживания (Service) выполняет запрос, если он не был выполнен на этапах PreExit или PostAuthorization.
На этом этапе допустимы все библиотечные функции сервера.
Информация о том, как настроить функцию для этапа Service на основе метода HTTP, а не на основе URL, приведена в описании директивы Enable в руководстве WebSphere Application Server Caching Proxy Administration Guide.
Для этого этапа необходимо реализовать следующие четыре функции. (Имена ваших функций могут отличаться от приведенных.)
void * HTTPD_LINKAGE openFunction ( unsigned char *handle, long *return_code )
Функция открытия (open) выполняет инициализацию (например, выделение буферов), необходимую для обработки данных из потока. Любой код возврата, отличный от HTTP_OK, приводит к аварийному прерыванию обработки (в этом случае функции write и close не вызываются). Ваша функция может вернуть пустой указатель, т.е. вы можете выделить пространство для структуры и снова получить указатель в параметре correlator последующих функций.
void HTTPD_LINKAGE writeFunction ( unsigned char *handle, unsigned char *data, /* данные ответа, переданные исходным сервером */ unsigned long *length, /* длина данных ответа */ void *correlator, /* указатель, возвращенный функцией 'open' */ long *return_code )
Функция записи (write) обрабатывает данные и может вызвать библиотечную функцию сервера HTTPD_write() с использованием новых или измененных данных. Модуль не должен пытаться освобождать полученный буфер и не должен ожидать, что сервер освободит полученный буфер.
Даже если вы решили не изменять данные в области действия своей функции записи, то для передачи данных ответа клиенту вам все равно нужно будет вызвать функцию HTTPD_write() в области действия функции open, write или close. Аргумент correlator - это указатель на буфер данных, возвращенный в функции open.
void HTTPD_LINKAGE closeFunction ( unsigned char *handle, void *correlator, long *return_code )
Функция закрытия (close) выполняет все действия по очистке (такие как освобождение памяти и очистка буфера correlator), необходимые для завершения обработки данных в текущем потоке. Аргумент correlator - это указатель на буфер данных, возвращенный в функции open.
void HTTPD_LINKAGE errorFunction ( unsigned char *handle, void *correlator, long *return_code )
Функция обработки ошибок (error) позволяет выполнить необходимые действия по очистке или/или освобождению памяти перед отправкой страницы с сообщением об ошибке. На этом этапе вызываются ваши функции open, write и close, обрабатывающие страницу с сообщением об ошибке. Аргумент correlator - это указатель на буфер данных, возвращенный в функции open.
Примечания:
void HTTPD_LINKAGE GCAdvisorFunction ( unsigned char *handle, long *return_code )
Определенная для этого этапа функция вызывается для каждого находящегося в кэше файла во время сбора мусора. Эта функция позволяет вам оказывать влияние на то, какие файлы должны сохраняться в кэше, а какие - удаляться. Дополнительная информация приведена в описании переменных GC_*.
void HTTPD_LINKAGE ProxyAdvisorFunction ( unsigned char *handle, long *return_code )
Определенная для этого этапа функция вызывается во время обслуживания каждого запроса proxy. Например, она может применяться для установки переменной USE_PROXY.
void HTTPD_LINKAGE LogFunction ( unsigned char *handle, long *return_code )
Определенная для этого этапа функция вызывается для каждого запроса после его обработки и закрытия соединения с клиентом. Если вы хотите, чтобы функция модуля вызывалась только для запросов, соответствующих определенному шаблону, то необходимо указать такой шаблон URL в директиве файла конфигурации. Эта функция вызывается независимо от результата обработки запроса. Если вы не хотите, чтобы ваш модуль переопределял механизм ведения протоколов по умолчанию, то вместо кода возврата HTTP_OK передайте код HTTP_NOACTION.
void HTTPD_LINKAGE ErrorFunction ( unsigned char *handle, long *return_code )
Определенная для этого этапа функция вызывается для всех запросов, при выполнении которых возникли ошибки. Если вы хотите, чтобы функция модуля вызывалась только для запросов с ошибками, соответствующих определенному шаблону, то необходимо указать такой шаблон URL в директиве файла конфигурации. Этот этап предоставляет возможность настройки алгоритма обработки ошибок.
void HTTPD_LINKAGE PostExitFunction ( unsigned char *handle, long *return_code )
Определенная для этого этапа функция вызывается для каждого запроса, независимо от результата его обработки. Данный этап позволяет выполнить задачи очистки ресурсов, выделенных в модуле во время обработки запроса.
void HTTPD_LINKAGE ServerTermFunction ( unsigned char *handle, long *return_code )
Определенная для этого этапа функция вызывается во время нормального завершения работы сервера. Она позволяет выполнить очистку ресурсов, выделенных на этапе ServerInit. На этом этапе не следует вызывать функции HTTP_* (результат может оказаться непредсказуемым). Если в файле конфигурации для этапа ServerTerm указано несколько директив с API Caching Proxy, то они все будут последовательно вызваны.
Эти коды возврата соответствуют спецификации HTTP 1.1, RFC 2616, опубликованной консорциумом World Wide Web (www.w3.org/pub/WWW/Protocols/). Функции вашего модуля должны возвращать одно из этих значений.
Значение | Код возврата |
0 | HTTP_NOACTION |
100 | HTTP_CONTINUE |
101 | HTTP_SWITCHING_PROTOCOLS |
200 | HTTP_OK |
201 | HTTP_CREATED |
202 | HTTP_ACCEPTED |
203 | HTTP_NON_AUTHORITATIVE |
204 | HTTP_NO_CONTENT |
205 | HTTP_RESET_CONTENT |
206 | HTTP_PARTIAL_CONTENT |
300 | HTTP_MULTIPLE_CHOICES |
301 | HTTP_MOVED_PERMANENTLY |
302 | HTTP_MOVED_TEMPORARILY |
302 | HTTP_FOUND |
303 | HTTP_SEE_OTHER |
304 | HTTP_NOT_MODIFIED |
305 | HTTP_USE_PROXY |
307 | HTTP_TEMPORARY_REDIRECT |
400 | HTTP_BAD_REQUEST |
401 | HTTP_UNAUTHORIZED |
403 | HTTP_FORBIDDEN |
404 | HTTP_NOT_FOUND |
405 | HTTP_METHOD_NOT_ALLOWED |
406 | HTTP_NOT_ACCEPTABLE |
407 | HTTP_PROXY_UNAUTHORIZED |
408 | HTTP_REQUEST_TIMEOUT |
409 | HTTP_CONFLICT |
410 | HTTP_GONE |
411 | HTTP_LENGTH_REQUIRED |
412 | HTTP_PRECONDITION_FAILED |
413 | HTTP_ENTITY_TOO_LARGE |
414 | HTTP_URI_TOO_LONG |
415 | HTTP_BAD_MEDIA_TYPE |
416 | HTTP_BAD_RANGE |
417 | HTTP_EXPECTATION_FAILED |
500 | HTTP_SERVER_ERROR |
501 | HTTP_NOT_IMPLEMENTED |
502 | HTTP_BAD_GATEWAY |
503 | HTTP_SERVICE_UNAVAILABLE |
504 | HTTP_GATEWAY_TIMEOUT |
505 | HTTP_BAD_VERSION |
Из своих собственных модулей вы можете вызывать библиотечные макросы и функции сервера. При этом необходимо использовать описанные ниже имена и форматы. В описаниях параметров буква i обозначает входной параметр, буква o - выходной, а буквы i/o указывают, что параметр используется как для ввода, так и для вывода информации.
Каждая из этих функций возвращает один их кодов возврата HTTPD, в зависимости от того, насколько успешно выполнен запрос. Эти коды описаны в разделе Коды возврата заранее определенных функций и макросов.
При вызове этих функций в качестве первого параметра необходимо указывать описатель, предоставленный вашему модулю. В противном случае функция вернет код ошибки HTTPD_PARAMETER_ERROR. Значение NULL недопустимо в качестве описателя.
void HTTPD_LINKAGE HTTPD_authenticate ( unsigned char *handle, /* i; описатель */ long *return_code /* o; код возврата */ )
void HTTPD_LINKAGE HTTPD_cacheable_url ( unsigned char *handle, /* i; описатель */ unsigned char *url, /* i; проверяемый URL */ unsigned char *req_method, /* i; метод запроса для URL */ long *retval /* o; код возврата */ )
Возвращенное значение HTTPD_SUCCESS указывает, что информация с данным URL может кэшироваться. Значение HTTPD_FAILURE указывает,что кэширование запрещено. Эта функция может также вернуть значение HTTPD_INTERNAL_ERROR.
void HTTPD_LINKAGE HTTPD_close ( unsigned char *handle, /* i; описатель */ long *return_code /* o; код возврата */ )
void HTTPD_LINKAGE HTTPD_exec ( unsigned char *handle, /* i; описатель */ unsigned char *name, /* i; имя выполняемого сценария */ unsigned long *name_length, /* i; длина имени */ long *return_code /* o; код возврата */ )
void HTTPD_LINKAGE HTTPD_extract ( unsigned char *handle, /* i; описатель */ unsigned char *name, /* i; имя извлекаемой переменной */ unsigned long *name_length, /* i; длина имени */ unsigned char *value, /* o; буфер для размещения значения */ unsigned long *value_length, /* i/o; размер буфера */ long *return_code /* o; код возврата */ )
Если эта функция возвращает код HTTPD_BUFFER_TOO_SMALL, значит размер запрошенного буфера был недостаточен для извлеченного значения. В этом случае функция не использует буфер, но указывает в параметре value_length размер буфера, необходимый для успешного извлечения значения. Повторите операцию с буфером, размер которого равен или больше возвращенному значению value_length.
void HTTPD_LINKAGE HTTPD_file ( unsigned char *handle, /* i; описатель */ unsigned char *name, /* i; имя отправляемого файла */ unsigned long *name_length, /* i; длина имени */ long *return_code /* o; код возврата */ )
const unsigned char * /* o; значение переменной*/ HTTPD_LINKAGE httpd_getvar( unsigned char *handle, /* i; описатель */ unsigned char *name, /* i; имя переменной */ unsigned long *n /* i; индекс массива заголовка */ )
Индекс массива начинается с 0. Для получения первого элемента массива укажите значение n, равное 0; для получения пятого элемента - значение n, равное 4.
void HTTPD_LINKAGE HTTPD_log_access ( unsigned char *handle, /* i; описатель */ unsigned char *value, /* i; записываемые данные */ unsigned long *value_length, /* i; длина данных */ long *return_code /* o; код возврата */ )
Обратите внимание, что для записи символа процента (%) в протокол доступа сервера escape-символы не нужны.
void HTTPD_LINKAGE HTTPD_log_error ( unsigned char *handle, /* i; описатель */ unsigned char *value, /* i; записываемые данные */ unsigned long *value_length, /* i; длина данных */ long *return_code /* o; код возврата */ )
Обратите внимание, что для записи символа процента (%) в протокол ошибок сервера escape-символы не нужны.
void HTTPD_LINKAGE HTTPD_log_event ( unsigned char *handle, /* i; описатель */ unsigned char *value, /* i; записываемые данные */ unsigned long *value_length, /* i; длина данных */ long *return_code /* o; код возврата */ )
Обратите внимание, что для записи символа процента (%) в протокол событий сервера escape-символы не нужны.
void HTTPD_LINKAGE HTTPD_log_trace ( unsigned char *handle, /* i; описатель */ unsigned char *value, /* i; записываемые данные */ unsigned long *value_length, /* i; длина данных */ long *return_code /* o; код возврата */ )
Обратите внимание, что для записи символа процента (%) в протокол трассировки сервера escape-символы не нужны.
void HTTPD_LINKAGE HTTPD_open ( unsigned char *handle, /* i; описатель */ long *return_code /* o; код возврата */ )
void HTTPD_LINKAGE HTTPD_proxy ( unsigned char *handle, /* i; описатель */ unsigned char *url_name, /* i; URL для запроса proxy */ unsigned long *name_length, /* i; длина URL */ void *request_body, /* i; текст запроса */ unsigned long *body_length, /* i; длина текста */ long *return_code /* o; код возврата */ )
void HTTPD_LINKAGE HTTPD_read ( unsigned char *handle, /* i; описатель */ unsigned char *value, /* i; буфер данных */ unsigned long *value_length, /* i/o; размер буфера (длина данных) */ long *return_code /* o; код возврата */ )
void HTTPD_LINKAGE HTTPD_restart ( long *return_code /* o; код возврата */ )
Обратите внимание, что с помощью этой функции можно также создавать переменные. Создаваемые переменные должны отвечать требованиям соглашений для префиксов HTTP_ и PROXY_, описанным в разделе Переменные. При создании переменной с префиксом HTTP_ эта переменная отправляется клиенту вместе с ответом без префикса HTTP_. Например, для задания заголовка Location можно воспользоваться функцией HTTPD_set() с переменной HTTP_LOCATION. Переменные, создаваемые с префиксом PROXY_, отправляются как заголовки запроса серверу информационного наполнения. Переменные, созданные с префиксом CGI_, передаются программам CGI.
Обратите внимание, что данная функция допустима на всех этапах, однако некоторые переменные допустимы не на всех этапах.
void HTTPD_LINKAGE HTTPD_set ( unsigned char *handle, /* i; описатель */ unsigned char *name, /* i; имя устанавливаемой переменной */ unsigned long *name_length, /* i; длина имени */ unsigned char *value, /* i; буфер со значением */ unsigned long *value_length, /* i; длина значения */ long *return_code /* o; код возврата */ )
long /* o; код возврата */ HTTPD_LINKAGE httpd_setvar ( unsigned char *handle, /* i; описатель */ unsigned char *name, /* i; имя переменной */ unsigned char *value, /* i; новое значение */ unsigned long *addHdr /* i; добавление или замена заголовка */ )
параметр addHdr может иметь одно из следующих четырех значений:
Эти переменные определены в файле HTAPI.h.
void HTTPD_LINKAGE httpd_variant_insert ( unsigned char *handle, /* i; описатель */ unsigned char *URI, /* i; URI объекта */ unsigned char *dimension, /* i; размеренность варианта */ unsigned char *variant, /* i; значение варианта */ unsigned char *filename, /* i; файл объекта */ long *return_code /* o; код возврата */ )
Примечания:
Mozilla 4.0 (compatible; BatBrowser 94.1.2; Bat OS)
void HTTPD_LINKAGE httpd_variant_lookup ( unsigned char *handle, /* i; описатель */ unsigned char *URI, /* URI объекта */ unsigned char *dimension, /* i; размеренность варианта */ unsigned char *variant, /* i; значение варианта */ long *return_code); /* o; код возврата */
Если вы не задали тип информации перед первым вызовом этой функции, то сервер предполагает, что передается поток данных CGI.
void HTTPD_LINKAGE HTTPD_write ( unsigned char *handle, /* i; описатель */ unsigned char *value, /* i; отправляемые данные */ unsigned char *value_length, /* i; длина данных */ long *return_code); /* o; код возврата */
В зависимости от того, насколько успешно выполнен запрос, сервер присвоит параметру кода возврата одно из следующих значений:
Значение | Код состояния | Описание |
---|---|---|
-1 | HTTPD_UNSUPPORTED | Функция не поддерживается. |
0 | HTTPD_SUCCESS | Функция выполнена успешно, все поля вывода допустимы. |
1 | HTTPD_FAILURE | При выполнении функции возникла ошибка. |
2 | HTTPD_INTERNAL_ERROR | Произошла внутренняя ошибка; продолжать обработку запроса невозможно. |
3 | HTTPD_PARAMETER_ERROR | Функции передан один или несколько недопустимых параметров. |
4 | HTTPD_STATE_CHECK | Функция недопустима на данном этапе обработки. |
5 | HTTPD_READ_ONLY | (Возвращается только функциями HTTPD_set и httpd_setvar.) Переменная предназначена только для чтения и ее значение нельзя задавать из модуля. |
6 | HTTPD_BUFFER_TOO_SMALL | (Возвращается функциями HTTPD_set, httpd_setvar и HTTPD_read.) Размер предоставленного буфера слишком мал. |
7 | HTTPD_AUTHENTICATE_FAILED | (Возвращается только функцией HTTPD_authenticate.) Ошибка идентификации. Дополнительная информация приведена в переменных HTTP_RESPONSE и HTTP_REASON. |
8 | HTTPD_EOF | (Возвращается только функцией HTTPD_read.) Указывает на завершение текста запроса. |
9 | HTTPD_ABORT_REQUEST | Запрос отменен, поскольку клиент предоставил тег объекта, не соответствующий указанным в запросе условиям. |
10 | HTTPD_REQUEST_SERVICED | (Возвращается функцией HTTPD_proxy.) Вызванная функция завершила создание ответа на запрос. |
11 | HTTPD_RESPONSE_ALREADY_COMPLETED | Функция не выполнена, поскольку ответ на этот запрос уже создан. |
12 | HTTPD_WRITE_ONLY | Переменная предназначена только для записи и ее значение нельзя считывать из модуля. |
Для каждого этапа обработки запроса существует директива конфигурации, с помощью которой вы можете указать, какая функция модуля должна вызываться и выполняться на этом этапе. Вы можете добавить эти директивы в файл конфигурации сервера (ibmproxy.conf) вручную или с помощью формы API обработки запросов в интерфейсе администрирования и настройки Caching Proxy.
Это значит, что сервер обрабатывает директивы Service, NameTrans, Exec, Fail, Map, Pass, Proxy, ProxyWAS и Redirect в том порядке, в котором они встречаются в файле конфигурации. Когда сервер успешно устанавливает соответствие между URL и файлом, он больше не считывает и не обрабатывает последующие директивы. (Исключением является директива Map. Подробная информация о правилах преобразования записей сервера proxy приведена в книге WebSphere Application Server Caching Proxy Administration Guide.)
Следующие директивы файла конфигурации должны быть указаны в файле ibmproxy.conf на одной строке без лишних пробелов. Должны присутствовать лишь те пробелы, которые явно указаны в данной таблице. Несмотря на то, что в некоторых примерах для упрощения чтения директивы перенесены на новую строку, на самом деле в соответствующих позициях директив не должно быть пробелов.
Переменные в этих директивах имеют следующее значение:
Если необходимо обеспечить доступ к информации о пути, то в директиве Service после имени функции должна быть указана звездочка (*).
Дополнительная информация о директивах, включая описание синтаксиса, приведена в руководстве WebSphere Application Server Caching Proxy Administration Guide.
API Caching Proxy обеспечивают обратную совместимость с ICAPI и GWAPI вплоть до версии 4.6.1.
При портировании написанных на C приложений CGI в API Caching Proxy следует руководствоваться следующими правилами:
При написании программ для API можно использовать переменные компонента Caching Proxy, предоставляющие информацию об удаленной системе клиента и сервера.
Примечания:
ACCEPT_RANGES BYTES CLIENT_ADDR 9.67.84.3
Эта переменная может применяться на шагах PostAuthorization, PostExit, ProxyAdvisor или Log.
http://www.anynet.com/~userk/main.htm
Mon, 01 Mar 2002 19:41:17 GMT
Mon, 01 Mar 1998 19:41:17 GMT
d:\wwwhome\foo
/wwwhome/foo
application/x-www-form-urlencoded
7034
NAME=Eugene+T%2E+Fox&ADDR=etfox%7Cibm.net&INTEREST=xyz
http://www.company.com/homepage
application/x-www-form-urlencoded
Вначале определимся с применяемой терминологией:
Рис. 3 содержит описание процессов идентификации и проверки прав доступа сервером proxy.
Как показано на Рис. 3, процессы идентификации и проверки прав доступа начинаются с инициализации процесса проверки прав доступа.
В Caching Proxy идентификация является частью процесса проверки прав доступа и выполняется только в том случае, когда необходимо проверить наличие прав доступа.
При обработке запроса, требующего проверки прав доступа, сервер proxy выполняет следующие действия.
Если в вашем модуле Caching Proxy предусмотрен собственный процесс проверки прав доступа, то он переопределяет применяемые сервером по умолчанию процессы идентификации и проверки прав доступа. Таким образом, если в файле конфигурации присутствуют директивы проверки прав доступа, то связанные с этими директивами функции модуля должны также обрабатывать все необходимые процедуры идентификации. Вы можете использовать заранее определенную функцию HTTPD_authenticate().
Существует три способа обеспечения идентификации в модуле проверки прав доступа:
При выполнении этапа проверки прав доступа (Authorization) вызывается функция модули проверки прав доступа, которая в свою очередь вызывает функцию модуля идентификации.
При выполнении этапа проверки прав доступа (Authorization) вызывается функция модуля проверки прав доступа, которая в свою очередь вызывает функцию идентификации по умолчанию.
При выполнении этапа проверки прав доступа вызывается функция модуля проверки прав доступа с включенными в ее состав средствами идентификации.
Если в модуле Caching Proxy не предусмотрен собственный процесс проверки прав доступа, то с помощью следующих методов вы все равно можете включить собственный процесс идентификации:
При выполнении этапа проверки прав доступа (Authorization) вызывается функция проверки прав доступа по умолчанию, которая в свою очередь вызывает вашу функцию модуля идентификации.
Обратите внимание на следующие особенности:
Кэширование вариантов применяется для кэширования данных, представляющих собой видоизмененный вариант исходного документа (URI). Caching Proxy обрабатывает варианты, сформированные API. Варианты - это различные версии базового документа.
Обычно, когда исходные серверы отправляют варианты, они не указывают, что отправленные документы являются именно вариантами. Caching Proxy поддерживает только варианты, созданные модулями (например, при преобразовании кодовых страниц). Если модуль создает вариант документа на основе условия, не включенного в заголовок HTTP, то он должен с помощью функций этапа PreExit или PostAuthorization создать псевдозаголовок, который позволил бы Caching Proxy правильно идентифицировать существующие варианты.
Например, можно использовать программу API Transmogrifier для изменения запрошенных пользователями данных на основании отправленного браузером заголовка User-Agent. В функции close сохраните измененную информацию в файле или укажите длину буфера и передайте этот буфер как аргумент данных. После этого можно воспользоваться функциями кэширования вариантов httpd_variant_insert() и httpd_variant_lookup() для размещения варианта в кэше.
Вам будет проще начать разработку собственных функций API Caching Proxy, если вы ознакомитесь с примерами программ, находящимися в каталоге samples установочного компакт-диска Edge Components. Дополнительная информация приведена на Web-сайте WebSphere Application Server www.ibm.com/software/webservers/appserv/.
В этом разделе описывается создание пользовательских советников для компонента Load Balancer.
Советники - это программные посредники компонента Load Balancer, предоставляющие информацию о нагрузке на выбранном сервере. Для каждого стандартного протокола (HTTP, SSL и т.д.) существуют специальные советники. Периодически основной код компонента Load Balancer выполняет цикл советника, в течение которого анализируется состояние каждого сервера конфигурации.
Написание пользовательских советников для Load Balancer позволяет настроить параметры определения нагрузки серверов.
В операционных системах семейства Windows: Если используется протокол IPv6, то при установке Load Balancer для IPv4 и IPv6 необходимо изменить файл protocol, расположенный в каталоге C:\windows\system32\drivers\etc\.
Для использования протокола IPv6 необходимо вставить в файл следующую строку:
ipv6-icmp 58 IPv6-ICMP # IPv6 interface control message protocol
Как правило, советники выполняют распределение нагрузки следующим образом.
Стандартные советники, поставляемые вместе с компонентом Load Balancer, выполняют следующие функции. Подробная информация о советниках приведена в документе WebSphere Application Server Load Balancer Administration Guide
Для специальных протоколов, которые не поддерживаются стандартными советниками, необходимо создавать пользовательские советники.
Пользовательский советник представляет собой небольшой код на языке Java, сохраненный в виде файле класса, который вызывается основным кодом компонента Load Balancer для определения загрузки сервера. Основной код предоставляет все необходимые административные службы, включая запуск и остановку экземпляра пользовательского советника, информацию о статусе советника, отчеты, ведение журнала событий, а также передачу результатов работы советника компоненту диспетчера.
Процедура вызова пользовательского советника включает следующие этапы.
Пользовательские советники могут взаимодействовать с Load Balancer либо в обычном режиме работы, либо в режиме замены.
Режим работы задается при помощи специального параметра метода конструктора в файле пользовательского советника. (Каждый советник может работать только в одном режиме, в зависимости от своего назначения).
В обычном режиме работы пользовательский советник обменивается данными с сервером, измеряет время обмена и вычисляет значение нагрузки. Затем основной код передает значение нагрузки диспетчеру. В случае успеха пользовательский советник возвращает нулевое значение, в противном случае - отрицательное значение.
Для выбора обычного режима работы присвойте флагу замены в конструкторе значение false.
В режиме замены основной код не выполняет каких-либо измерений времени. Вместо этого он выполняет указанные пользователем операции, основанные на специальных требованиях, и возвращает фактическое значение нагрузки. После получения этого значения основной код передает его в том же виде диспетчеру. Для получения оптимального результата рекомендуется настроить значение нагрузки в диапазоне от 10 до 1000, где 10 обозначает быстродействующий сервер, а 1000 - медленный.
Для выбора режима замены присвойте флагу замены в конструкторе значение true.
Имя файла пользовательского советника должно быть указано в виде ADV_имя.java, где имя - это имя, выбранное для советника. Приставка ADV_ в начале полного имени файла должна содержать символы верхнего регистра, а все остальные символы должны быть указаны в нижнем регистре. Последнее требование позволяет вводить имя файла советника в команде запуска без учета регистра.
В соответствии с соглашениями об именах Java, имя класса, определенного в файле, должно совпадать с именем файла.
Пользовательские советники создаются на языке Java и компилируются при помощи компилятора Java, установленного в системе пользователя. В процедуре компиляции используются следующие файлы:
Во время компиляции переменная среды classpath должна указывать и на файл пользовательского советника, и на файл базовых классов. Команда компилятора может быть указана в следующем формате:
javac -classpath /opt/ibm/edge/lb/servers/lib/ibmnd.jar ADV_имя.java
В этом примере используется путь установки, принятый по умолчанию в операционных системах Linux и UNIX. Файлу советника присвоено имя ADV_имя.java, и он хранится в текущем каталоге.
В результате компиляции создается файл класса, ADV_имя.class. Перед запуском советника необходимо скопировать этот файл в каталог установочный_каталог/servers/lib/CustomAdvisors/.
Для запуска пользовательского советника необходимо сначала скопировать файл класса советника в каталог lib/CustomAdvisors/ в системе, где установлен Load Balancer. Например, пользовательский советник с именем myping (ADV_myping.class) находится в каталоге установочный_каталог/servers/lib/CustomAdvisors/
Настройте Load Balancer, запустите диспетчер и выполните команду для запуска пользовательского советника. Для запуска пользовательского советника необходимо указать его имя без приставки ADV_ и расширения файла:
dscontrol advisor start myping номер_порта
Указанный в команде номер порта - это порт, к которому подключается советник при установлении соединения с целевым сервером.
Как и все стандартные советники, пользовательский советник расширяет функциональные возможности базового класса советника, ADV_Base. Базовый класс выполняет большинство функций советника, например, передает значения нагрузки диспетчеру для дальнейшей обработки. Кроме того, он создает сокеты и закрывает операции, а также содержит методы отправки и приема, необходимые для работы советника. Советник применяется исключительно для обмена данными с исследуемым сервером через указанный порт. Методы базового класса советника, основанные на протоколе TCP, используются для вычисления нагрузки. При необходимости для замены текущего значения нагрузки на новое значение, возвращаемое советником, можно использовать специальный флаг в конструкторе базового класса советника.
Советники содержат следующие методы базового класса:
Более подробную информацию об этих процедурах можно найти ниже.
Пользовательские советники вызываются, если поиск среди стандартных советников не дал результата. Если компоненту Load Balancer не удалось найти требуемый советник в списке стандартных советников, он просматривает список пользовательских советников. Дополнительная информация об использовании советников приведена в документе WebSphere Application Server Load Balancer Administration Guide.
При работе с пользовательскими советниками необходимо выполнять следующие требования к именам файлов и путям.
void ADV_Base Constructor ( string sName; string sVersion; int iDefaultPort; int iInterval; string sDefaultLogFileName; boolean replace )
void ADV_AdvisorInitialize()
Этот метод применяется для инициализации пользовательского советника. Этот метод вызывается после запуска базового модуля советника.
Обычно (в том числе и в стандартных советниках) этот метод не используется и содержит только оператор return. Этот метод может применяться для вызова метода suppressBaseOpeningSocket, который действителен только при вызове из метода ADV_AdvisorInitialize().
int getLoad( int iConnectTime; ADV_Thread *caller )
В следующих разделах описываются методы (или функции), вызываемые из пользовательских советников. Эти методы поддерживаются основным кодом советника.
Некоторые из этих функций могут быть вызваны напрямую, например, имя_функции(), а для других необходимо указывать приставку caller. Приставка Caller обозначает экземпляр базового советника, который поддерживает запущенный пользовательский советник.
Функция ADVLOG применяется для записи текстового сообщения в файл журнала советника. Формат:
void ADVLOG (int logLevel, string message)
Функция getAdvisorName возвращает Java-строку с суффиксом, который указывает имя пользовательского советника. Например, для советника ADV_cdload.java эта функция возвращает значение cdload.
У этой функции нет параметров.
Обратите внимание, что это значение не изменяется в процессе создания одного экземпляра советника.
Функция getAdviseOnPort возвращает номер порта, к которому подключен пользовательский советник. Возвращаемое значение представляет собой целое число Java (int). У этой функции нет параметров.
Обратите внимание, что это значение не изменяется в процессе создания одного экземпляра советника.
Функция getCurrentServer возвращает IP-адрес текущего сервера. Возвращаемое значение представляет собой строку Java в формате IP-адреса, например, 128.0.72.139
Обычно этот адрес изменяется при каждом вызове пользовательского советника, поскольку основной код советника последовательно отпрашивает все серверы.
У этой функции нет параметров.
Функция getCurrentCluster возвращает IP-адрес кластера сервера. Возвращаемое значение представляет собой строку Java в формате IP-адреса, например, 128.0.72.139
Обычно этот адрес изменяется при каждом вызове пользовательского советника, поскольку основной код советника последовательно опрашивает все кластеры сервера.
У этой функции нет параметров.
Функция getInterval возвращает интервал советника, т.е. число секунд между циклами советника. Это значение равно значению по умолчанию, указанному в конструкторе пользовательского советника, если оно не было изменено во время выполнения с помощью команды dscontrol.
Возвращаемое значение представляет собой целое число Java (int). У этой функции нет параметров.
Функция getLatestLoad позволяет получить последнее значение нагрузки для заданного сервера. Значения нагрузки сохраняются во внутренних таблицах основным кодом советника и демоном диспетчера.
int caller.getLatestLoad (string cluster_IP, int port, string server_IP)
Для определения одного объекта сервера необходимо три аргумента.
Возвращаемое значение представляет собой целое число.
Эта функция применяется, когда необходимо, чтобы поведение одного протокола или порта зависело от поведения другого протокола или порта. Например, эта функция может применяться в пользовательском советнике для отключения определенного сервера приложений, если сервер Telnet на том же самом компьютере отключен.
Функция receive принимает данные от сокета.
caller.receive(stringbuffer *response)
Параметр response представляет собой буфер, в который помещаются принятые данные. Функция возвращает одно из следующих значений:
Функция send использует установленное соединение для отправки пакета данных на сервер через указанный порт.
caller.send(string command)
Параметр command представляет собой строку, содержащую данные для передачи серверу. Функция возвращает одно из следующих значений:
Функция suppressBaseOpeningSocket позволяет основному коду советника установить TCP-соединение с сервером от имени пользовательского советника. Если советник не использует прямое соединение с сервером для определения его состояния, создавать данный сокет не требуется.
Данная функция вызывается из процедуры ADV_AdvisorInitialize, причем только один раз.
У этой функции нет параметров.
Ниже приведены примеры использования пользовательских советников.
Следующий пример исходного кода похож на код для стандартного советника компонента Load Balancer на базе HTTP-протокола. Процедура выполнения:
Этот советник работает в обычном режиме, поэтому значение нагрузки вычисляется на основе времени (в мс), необходимого для создания сокета и выполнения операций отправки, приема и закрытия.
package CustomAdvisors; import com.ibm.internet.lb.advisors.*; public class ADV_sample extends ADV_Base implements ADV_MethodInterface { static final String ADV_NAME ="Sample"; static final int ADV_DEF_ADV_ON_PORT = 80; static final int ADV_DEF_INTERVAL = 7; static final string ADV_SEND_REQUEST = "HEAD / HTTP/1.0\r\nAccept: */*\r\nUser-Agent: " + "IBM_Load_Balancer_HTTP_Advisor\r\n\r\n"; //-------- // Конструктор public ADV_sample() { super(ADV_NAME, "3.0.0.0-03.31.00", ADV_DEF_ADV_ON_PORT, ADV_DEF_INTERVAL, "", false); super.setAdvisor( this ); } //-------- // ADV_AdvisorInitialize public void ADV_AdvisorInitialize() { return; // обычно пустая процедура } //-------- // getLoad public int getLoad(int iConnectTime, ADV_Thread caller) { int iRc; int iLoad = ADV_HOST_INACCESSIBLE; // инициализируется // значением inaccessible iRc = caller.send(ADV_SEND_REQUEST); // отправляет HTTP-запрос // серверу if (0 <= iRc) { // если операция отправки выполнена успешно StringBuffer sbReceiveData = new StringBuffer(""); // выделение буфера // для ответа iRc = caller.receive(sbReceiveData); // получение результата // анализ полученного результата if (0 <= iRc) { // если операция приема выполнена успешно iLoad = 0; // возвращает 0 в случае успеха } // (значение нагрузки советника игнорируется } // в обычном режиме) return iLoad; } }
Этот пример демонстрирует закрытие стандартного сокета, созданного основным кодом советника. Вместо него советник открывает сокет с побочным потоком Java для соединения с сервером. Данная процедура применяется в том случае, если сервер использует для приема запросов советника нестандартный порт.
В данном примере сервер использует порт 11999 и при получении запроса возвращает значение нагрузки с шестнадцатеричным целым числом "4". В этом случае советник работает в режиме замены, т.е. последнему параметру конструктора советника присвоено значение true, и основной код советника использует вместо прошедшего времени возвращаемое значение нагрузки.
Обратите внимание на функцию supressBaseOpeningSocket() в процедуре инициализации. Закрывать сокет, если данные не отправляются, не требуется. Например, создание сокета может потребоваться для проверки возможности установления соединения с сервером. Перед использованием данного примера определите назначение вашего приложения.
package CustomAdvisors; import java.io.*; import java.net.*; import java.util.*; import java.util.Date; import com.ibm.internet.lb.advisors.*; import com.ibm.internet.lb.common.*; import com.ibm.internet.lb.server.SRV_ConfigServer; public class ADV_sidea extends ADV_Base implements ADV_MethodInterface { static final String ADV_NAME = "sidea"; static final int ADV_DEF_ADV_ON_PORT = 12345; static final int ADV_DEF_INTERVAL = 7; // создание массива байт с сообщением-запросом о нагрузке static final byte[] abHealth = {(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x04}; public ADV_sidea() { super(ADV_NAME, "3.0.0.0-03.31.00", ADV_DEF_ADV_ON_PORT, ADV_DEF_INTERVAL, "", true); // значение параметра режима замены равно true super.setAdvisor( this ); } //-------- // ADV_AdvisorInitialize public void ADV_AdvisorInitialize() { suppressBaseOpeningSocket(); // сообщает основному коду о том, что не нужно // создавать стандартный сокет return; } //-------- // getLoad public int getLoad(int iConnectTime, ADV_Thread caller) { int iRc; int iLoad = ADV_HOST_INACCESSIBLE; // -1 int iControlPort = 11999; // порт для подключения к серверу string sServer = caller.getCurrentServer(); // адреса сервера try { socket soServer = new Socket(sServer, iControlPort); // создать сокет // для сервера DataInputStream disServer = new DataInputStream( soServer.getInputStream()); DataOutputStream dosServer = new DataOutputStream( soServer.getOutputStream()); int iRecvTimeout = 10000; // задает значение тайм-аута (в мс) // для приема данных soServer.setSoTimeout(iRecvTimeout); dosServer.writeInt(4); // отправляет сообщение серверу dosServer.flush(); iLoad = disServer.readByte(); // получает ответ от сервера } catch (exception e) { system.out.println("Caught exception " + e); } return iLoad; // возвращает значение нагрузки для сервера } }
Следующий пример пользовательского советника демонстрирует возможность обнаружения сбоя одного порта сервера на основании его собственного состояния и состояния другого демона сервера, запущенного для другого порта того же сервера. Например, если демон HTTP перестает отвечать через порт 80, может потребоваться остановить перенаправление трафика демону SSL через порт 443.
Этот советник ведет себя агрессивнее, чем стандартные советники, поскольку любой сервер, который не отправляет ответ на его запрос, рассматривается ним как приостановленный и помечается как отключенный. Стандартные советники считают, что если сервер не отвечает, то он очень медленный. Этот же советник помечает сервер как отключенный как для порта HTTP, так и для порта SSL на основании отсутствия ответа от одного из них.
Для использования этого пользовательского советника администратор должен запустить два экземпляра советника: один для порта HTTP и второй для порта SSL. Посредник создает два экземпляра статических глобальных хэш-таблиц: один для порта HTTP и второй для порта SSL. В этих хэш-таблицах хранятся результаты попыток советника установить соединение с соответствующим демоном сервера. Значение, возвращаемое каждым советником в базовый класс советника, зависит от его способности установить соединение с собственным демоном сервера и способности другого советника установить соединение со своим демоном.
Используются следующие методы:
Обнаруживаются следующие условия возникновения ошибок:
В следующем примере программы используется порт 80 для протокола HTTP и порт 443 для протокола SSL, однако вместо них можно указать любую другую комбинацию портов.
package CustomAdvisors; import java.io.*; import java.net.*; import java.util.*; import java.util.Date; import com.ibm.internet.lb.advisors.*; import com.ibm.internet.lb.common.*; import com.ibm.internet.lb.manager.*; import com.ibm.internet.lb.server.SRV_ConfigServer; //-------- // Определение элементов хэш-таблиц в пользовательском советнике class ADV_nte implements Cloneable { private string sCluster; private int iPort; private string sServer; private int iLoad; private Date dTimestamp; //-------- // конструктор public ADV_nte(string sClusterIn, int iPortIn, string sServerIn, int iLoadIn) { sCluster = sClusterIn; iPort = iPortIn; sServer = sServerIn; iLoad = iLoadIn; dTimestamp = new Date(); } //-------- // проверка срока действия элемента public boolean isCurrent(ADV_twop oThis) { boolean bCurrent; int iLifetimeMs = 3 * 1000 * oThis.getInterval(); // присвоить параметру срока действия // значение, равное трем циклам советника Date dNow = new Date(); Date dExpires = new Date(dTimestamp.getTime() + iLifetimeMs); if (dNow.after(dExpires)) { bCurrent = false; } else { bCurrent = true; } return bCurrent; } //-------- // получение значения public int getLoadValue() { return iLoad; } //-------- // дубликат (позволяет избежать повреждения между нитями) public synchronized Object Clone() { try { return super.clone(); } catch (cloneNotSupportedException e) { return null; } } } //-------- // определение пользовательского советника public class ADV_twop extends ADV_Base implements ADV_MethodInterface, ADV_AdvisorVersionInterface { static final int ADV_TWOP_PORT_HTTP = 80; static final int ADV_TWOP_PORT_SSL = 443; //-------- // определение таблиц для хранения информации о портах static HashTable htTwopHTTP = new Hashtable(); static HashTable htTwopSSL = new Hashtable(); static final String ADV_TWOP_NAME = "twop"; static final int ADV_TWOP_DEF_ADV_ON_PORT = 80; static final int ADV_TWOP_DEF_INTERVAL = 7; static final string ADV_HTTP_REQUEST_STRING = "HEAD / HTTP/1.0\r\nAccept: */*\r\nUser-Agent: " + "IBM_LB_Custom_Advisor\r\n\r\n"; //-------- // создание массива байт с приветственным сообщением SSL-клиента public static final byte[] abClientHello = { (byte)0x80, (byte)0x1c, (byte)0x01, // приветственное сообщение клиента (byte)0x03, (byte)0x00, // версия протокола SSL (byte)0x00, (byte)0x03, // длина ключа (в байтах) (byte)0x00, (byte)0x00, // длина ИД сеанса (в байтах) (byte)0x00, (byte)0x10, // длина данных вызова (в байтах) (byte)0x00, (byte)0x00, (byte)0x03, // спецификация шифра (byte)0x1A, (byte)0xFC, (byte)0xE5, (byte)Ox20, // данные вызова (byte)0xFD, (byte)0x3A, (byte)0x3C, (byte)0x18, (byte)0xAB, (byte)0x67, (byte)0xB0, (byte)0x52, (byte)0xB1, (byte)0x1D, (byte)0x55, (byte)0x44, (byte)0x0D, (byte)0x0A }; //-------- // конструктор public ADV_twop() { super(ADV_TWOP_NAME, VERSION, ADV_TWOP_DEF_ADV_ON_PORT, ADV_TWOP_DEF_INTERVAL, "", false); // false = load balancer измеряет время ответа setAdvisor ( this ); } //-------- // ADV_AdvisorInitialize public void ADV_AdvisorInitialize() { return; } //-------- // синхронизированные процедуры доступа PUT и GET для хэш-таблиц synchronized ADV_nte getNte(Hashtable ht, String sName, String sHashKey) { ADV_nte nte = (ADV_nte)(ht.get(sHashKey)); if (null != nte) { nte = (ADV_nte)nte.clone(); } return nte; } synchronized void putNte(Hashtable ht, String sName, String sHashKey, ADV_nte nte) { ht.put(sHashKey,nte); return; } //-------- // getLoadHTTP - определение нагрузки HTTP на основе ответа сервера int getLoadHTTP(int iConnectTime, ADV_Thread caller) { int iLoad = ADV_HOST_INACCESSIBLE; int iRc = caller.send(ADV_HTTP_REQUEST_STRING); // отправляет сообщение-запрос // для сервера if (0 <= iRc) { // произошел сбой? StringBuffer sbReceiveData = new StringBuffer("") // выделение буфера // для ответа iRc = caller.receive(sbReceiveData); // получение ответа от сервера if (0 <= iRc) { // произошел сбой? if (0 < sbReceiveData.length()) { // приняты ли данные? iLoad = SUCCESS; // игнорирует принятые данные и // возвращает код SUCCESS } } } return iLoad; } //-------- // getLoadSSL() - определение нагрузки SSL на основе ответа сервера int getLoadSSL(int iConnectTime, ASV_Thread caller) { int iLoad = ADV_HOST_INACCESSIBLE; int iSocket = caller.getAdvisorSocket(); // отправляет запрос серверу CMNByteArrayWrapper cbawClientHello = new CMNByteArrayWrapper( abClientHello); int iRc = SRV_ConfigServer.socketapi.sendBytes(iSocket, cbawClientHello); if (0 <= iRc) { // произошел сбой? StringBuffer sbReceiveData = new StringBuffer(""); // выделение буфера // для ответа iRc = caller.receive(sbReceiveData); // получение ответа от // серверу if (0 <= iRc) { // произошел сбой? if (0 < sbReceiveData.length()) { // приняты ли данные? iLoad = SUCCESS; // игнорирует принятые данные и возвращает код SUCCESS } } } return iLoad; } //-------- // getLoad - объединение результатов методов HTTP и SSL public int getLoad(int iConnectTime, ADV_Thread caller) { int iLoadHTTP; int iLoadSSL; int iLoad; int iRc; String sCluster = caller.getCurrentCluster(); // текущий адрес кластера int iPort = getAdviseOnPort(); String sServer = caller.getCurrentServer(); String sHashKey = sCluster = ":" + sServer; // ключ хэш-таблицы if (ADV_TWOP_PORT_HTTP == iPort) { // обработка HTTP-сервера iLoadHTTP = getLoadHTTP(iConnectTime, caller); // получение значения нагрузки для HTTP ADV_nte nteHTTP = newADV_nte(sCluster, iPort, sServer, iLoadHTTP); putNte(htTwopHTTP, "HTTP", sHashKey, nteHTTP); // сохранение значения нагрузки // о протоколе SSL ADV_nte nteSSL = getNte(htTwopSSL, "SSL", sHashKey); // получение информации // для протокола HTTP if (null != nteSSL) { if (true == nteSSL.isCurrent(this)) { // проверка временной метки if (ADV_HOST_INACCESSIBLE != nteSSL.getLoadValue()) { // работает ли SSL? iLoad = iLoadHTTP; } else { // SSL не работает, поэтому HTTP-сервер // помечается как отключенный iLoad= ADV_HOST_INACCESSIBLE; } } else { // срок действия информации SSL истек, поэтому // HTTP-сервер помечается как отключенный iLoad = ADV_HOST_INACCESSIBLE; } } else { // значение нагрузки для SSL отсутствует, передача // результатов выполнения метода getLoadHTTP() iLoad = iLoadHTTP; } } else if (ADV_TWOP_PORT_SSL == iPort) { // обработка SSL-сервера iLoadSSL = getLoadSSL(iConnectTime, caller); // получение значения нагрузки для SSL ADV_nte nteSSL = new ADV_nte(sCluster, iPort, sServer, iLoadSSL); putNte(htTwopSSL, "SSL", sHashKey, nteSSL); // сохранение информации о нагрузке для SSL ADV_nte nteHTTP = getNte(htTwopHTTP, "SSL", sHashKey); // получение информации // для протокола HTTP if (null != nteHTTP) { if (true == nteHTTP.isCurrent(this)) { // проверка временной метки if (ADV_HOST_INACCESSIBLE != nteHTTP.getLoadValue()) { // работает ли SSL? iLoad = iLoadSSL; } else { // HTTP-сервер не работает, поэтому он // помечается как отключенный iLoad = ADV_HOST_INACCESSIBLE; } } else { // срок действия информации HTTP истек, // сервер помечается как отключенный iLoad = ADV_HOST_INACCESSIBLE; } } else { // значение нагрузки для HTTP отсутствует, передача // результатов выполнения метода getLoadSSL() iLoad = iLoadSSL; } } //-------- // обработчик ошибок else { iLoad = ADV_HOST_INACCESSIBLE; } return iLoad; } }
Пример пользовательского советника для сервера WebSphere Application Server расположен в каталоге установочный_каталог/servers/samples/CustomAdvisors/. В этом документе приводится только часть исходного кода.
Полный текст исходного кода советника намного сложнее приведенного здесь отрывка. В него добавлена специальная процедура анализа, более компактная по сравнению с процедурой StringTokenizer (см. пример выше).
Более сложная часть исходного кода содержится в файле сервлета Java. Кроме того, сервлет содержит два метода, необходимых в соответствии со спецификацией сервлета: init() и service(), и еще один метод: run(), необходимый для класса Java.lang.thread.
Ниже приведены некоторые фрагменты кода сервлета.
... public void init(ServletConfig config) throws ServletException { super.init(config); ... _checker = new Thread(this); _checker.start(); } public void run() { setStatus(GOOD); while (true) { if (!getKeepRunning()) return; setStatus(figureLoad()); setLastUpdate(new java.util.Date()); try { _checker.sleep(_interval * 1000); } catch (Exception ignore) { ; } } } public void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { ServletOutputStream out = null; try { out = res.getOutputStream(); } catch (Exception e) { ... } ... res.setContentType("text/x-application-LBAdvisor"); out.println(getStatusString()); out.println(getLastUpdate().toString()); out.flush(); return; } ...
Как при использовании стандартных функций, так и при добавлении новых функций к исходному коду пользовательского советника возникает необходимость проверить возвращаемые значения нагрузки и выполнить соответствующие действия. Для этой цели используются Java-класс StringTokenizer и связанные методы.
Пример стандартной команды HTTP: GET /index.html HTTP/1.0
Стандартный ответ на эту команду выглядит следующим образом:
HTTP/1.1 200 OK Date: Mon, 20 November 2000 14:09:57 GMT Server: Apache/1.3.12 (Linux and UNIX) Content-Location: index.html.en Vary: negotiate TCN: choice Last-Modified: Fri, 20 Oct 2000 15:58:35 GMT ETag: "14f3e5-1a8-39f06bab;39f06a02" Accept-Ranges: bytes Content-Length: 424 Connection: close Content-Type: text/html Content-Language: en <!DOCTYPE HTML PUBLIC "-//w3c//DTD HTML 3.2 Final//EN"> <HTML><HEAD><TITLE>Test Page</TITLE></HEAD> <BODY><H1>Apache server</H1> <HR> <P><P>This Web server is running Apache 1.3.12. <P><HR> <P><IMG SRC="apache_pb.gif" ALT=""> </BODY></HTML>
Наиболее важные элементы указаны в первой строке, в частности код возврата HTTP.
В соответствии со спецификацией протокола HTTP существуют следующие группы кодов возврата:
Если вам заранее известны возможные коды возврата сервера, такой уровень детализации данных, как в этом примере, вам может и не потребоваться. Следует отметить, что ограничение списка отслеживаемых кодов возврата может снизить гибкость вашей программы в будущем.
Ниже приведен пример автономной программы на языке Java, содержащей минимальный HTTP-клиент. Этот пример вызывает простой универсальный анализатор для проверки ответов HTTP.
import java.io.*; import java.util.*; import java.net.*; public class ParseTest { static final int iPort = 80; static final String sServer = "www.ibm.com"; static final String sQuery = "GET /index.html HTTP/1.0\r\n\r\n"; static final String sHTTP10 = "HTTP/1.0"; static final String sHTTP11 = "HTTP/1.1"; public static void main(String[] Arg) { String sHTTPVersion = null; String sHTTPReturnCode = null; String sResponse = null; int iRc = 0; BufferedReader brIn = null; PrintWriter psOut = null; Socket soServer= null; StringBuffer sbText = new StringBuffer(40); try { soServer = new Socket(sServer, iPort); brIn = new BufferedReader(new InputStreamReader( soServer.getInputStream())); psOut = new PrintWriter(soServer.getOutputStream()); psOut.println(sQuery); psOut.flush(); sResponse = brIn.readLine(); try { soServer.close(); } catch (Exception sc) {;} } catch (Exception swr) {;} StringTokenizer st = new StringTokenizer(sResponse, " "); if (true == st.hasMoreTokens()) { sHTTPVersion = st.nextToken(); if (sHTTPVersion.equals(sHTTP110) || sHTTPVersion.equals(sHTTP11)) { System.out.println("HTTP Version: " + sHTTPVersion); } else { System.out.println("Invalid HTTP Version: " + sHTTPVersion); } } else { System.out.println("Nothing was returned"); return; } if (true == st.hasMoreTokens()) { sHTTPReturnCode = st.nextToken(); try { iRc = Integer.parseInt(sHTTPReturnCode); } catch (NumberFormatException ne) {;} switch (iRc) { case(200): System.out.println("HTTP Response code: OK, " + iRc); break; case(400): case(401): case(402): case(403): case(404): System.out.println("HTTP Response code: Client Error, " + iRc); break; case(500): case(501): case(502): case(503): System.out.println("HTTP Response code: Server Error, " + iRc); break; default: System.out.println("HTTP Response code: Unknown, " + iRc); break; } } if (true == st.hasMoreTokens()) { while (true == st.hasMoreTokens()) { sbText.append(st.nextToken()); sbText.append(" "); } System.out.println("HTTP Response phrase: " + sbText.toString()); } } }