программирование, создание программ, учебник Delphi, учебник по программированию, бейсек, делфи, си, паскаль
 
 
 

 

История технологий, работающих с динамическим содержимым Web

До сегодняшнего дня было немало методик работы с динамическим содержимым Web. Самой старой из них, которая поддерживается большинством HTTP-серверов, является общий шлюзовой интерфейс (CGI). С помощью переменных среды, CGI-программа принимает данные заголовка HTTP-запроса, отправляемые с Web-броузера. Кроме того, такая программа, пользуясь перенаправленным стандартным входным потоком, принимает данные запроса через Web-сервер, а затем генерирует динамический HTML для передачи клиенту через тот же Web-сервер, используя перенаправленный стандартный выходной поток. Конечно, применение переменных среды, стандартных входного и выходного потоков является способом не слишком эффективным, зато работающим одинаково на большинстве Web-серверов, размещенных как в Unix, так и в Windows. К сожалению, для каждого клиентского запроса общий шлюзовой интерфейс (CGI) создает новый процесс, а это слишком дорого обходится с точки зрения производительности и использования ресурсов. Так что эффективно обработать большое количество клиентских запросов с помощью общего шлюзового интерфейса (CGI) не удается. К тому же, Web-сервер и CGI-процесс находятся в разных адресных пространствах. Поэтому общий шлюзовой интерфейс (CGI) страдает еще и от накладных расходов, вызываемых большим количеством взаимодействий между процессами.
Что касается интерфейса прикладного программирования Internet-сервера ISAPI, который представляет собой технологию на основе информационного сервера Internet (Internet Information Server, US), то он решает проблемы с производительностью и масштабированием, выполняя вместо CGI-процесса встроенную в процесс динамически подсоединяемую библиотеку (DLL) интерфейса прикладного программирования Internet-сервера (ISAPI), По требованию эта библиотека загружается в адресное пространство информационного сервера Internet (IIS) и совместно используется многими W/eb-клиентами. Интерфейс прикладного программирования Internet-сервера (ISAPI) содержит интерфейсы прикладного программирования (API), которые необходимы для доступа к клиентским запросам, и, в частности, ко входным параметрам и HTTP-заголовкам. Для чтения данных, находящихся в запросах, интерфейс прикладного программирования Internet-сервера (ISAPI) организует входной поток, а для отправки клиенту, в ответ на его запрос, динамически созданного HTML-кода — выходной поток. Такой подход намного эффективнее, чем использование общего шлюзового интерфейса CGI, потому что новый процесс не создается, и, следовательно, взаимодействие процессов на сервере не требуется. В среде Visual C++ 6.0 имеется ISAPI Extension Wizard (Мастер создания расширений интерфейса прикладного программирования Internet-сервера), предназначенный для создания на основе MFC расширений интерфейса прикладного программирования Internet-сервера. Кроме того, там имеются проекты фильтров для интерфейса прикладного программирования Internet-сервера (ISAPI). Для работы с интерфейсом прикладного программирования Internet-сервера (ISAPI) в библиотеке MFC предусмотрен CHttpServer, исполняющий роль оболочки в интерфейсе прикладного программирования Internet-служб, а также макрос для создания карты сообщений и макросы для различных преобразований в ходе грамматического разбора.
Фильтры и расширения интерфейса прикладного программирования Internet-сервера (ISAPI) прекрасно подходили для создания высокопроизводительных Web-приложений, однако требовали от программистов достаточно высокой квалификации. Этим специалистам нужно было не только знать C++, но также понимать и использовать организацию пула с помощью процессов, синхронизацию, обработку транзакций и безопасность. Помимо этого, программисту требовалось быть очень осторожным и перед размещением динамически подсоединяемой библиотеки (DLL) интерфейса прикладного программирования Internet-сервера (ISAPI), приходилось проводить большое количество испытанийСДёло в том, что любая достаточно серьезная ошибка в такой библиотеке, работающей в рамках того же процесса, что и информационный сервер Internet, привела бы к аварийному завершению всего процесса (то есть к аварийному завершению работы Web-сервера OS). И, наконец, большинство программистов возненавидело интерфейс прикладного программирования Internet-сервера (ISAPI). Причина здесь в том, что фильтры и расширения интерфейса прикладного программирования Internet-сервера (ISAPI) труднее поддаются отладке, чем другие программы, написанные на C++, так как необходимо подсоединяться к работающему процессу, в рамках которого выполняется информационный сервер Internet (П5).
Что касается технологии ASP, то для разработки на высоком уровне динамического Web-содержимого она является достаточно удобным средством. Эта технология использует интерфейс прикладного программирования Internet-сервера (ISAPI), но при этом не столь эффективна, как интерфейс прикладного программирования Internet-сервера (ISAPI) в чистом виде. ASP фактически реализована в виде заранее подготовленной, достаточно универсальной динамически подсоединяемой библиотеки (DLL) интерфейса прикладного программирования Internet-сервера (ISAPI), которая реализует машину сценариев. В свою очередь машина сценариев потом интерпретирует ASP-страницу. Такая страница похожа на обычную HTML-страницу, за исключением того, что содержит встроенные фрагменты ASP-кода, написанные в виде сценария. Этот код не компилируется, а интерпретируется машиной сценариев. Для интерпретации можно использовать любой язык подготовки сценариев, который установлен на Web-сервере, поддерживающем ASP. По умолчанию информационный сервер Internet (П5) автоматически поддерживает VBScript и JScript. Недостатком ASP является то, что интерпретируемый код, естественно, работает медленнее, чем выполняющий те же действия скомпилированный код, в котором используется интерфейс прикладного программирования Internet-сервера (ISAPI).
Другим недостатком ASP является то, что языки подготовки сценариев не обеспечивают типовую безопасность, что может привести к ошибкам времени выполнения, которые было бы лучше предотвратить еще во время компиляции. Ну и, наконец, языки подготовки сценариев не являются объектно-ориентированными и потому не могут служить в качестве языков программирования высокого^ уровня, используемых для программирования больших систем. А вот огромным преимуществом ASP является то, что языки подготовки сценариев обычно очень легкие для1 изучения. В частности, VBScript известен огромному числу людей. То, что языки подготовки сценариев, подобные VBScript, не являются объектно-ориентированными, частично компенсируется их способностью вызывать серверные СОМ-компоненты. Дело в том, что эти компоненты можно писать на мощных объектно-ориентированных языках, таких, как C++. Другое преимущество ASP перед интерфейсом прикладного программирования Internet-сервера (ISAPI) состоит в том, что ASP прекрасно подходит для работы с сервером транзакций корпорации Microsoft (Microsoft Transaction Server, MTS). Это дает возможность автоматизировать организацию поточной обработки, а также управление синхронизацией, обработкой транзакций и безопасностью.
Технология ASP.NET, к счастью, сохраняет все преимущества традиционной ASP и избавлена от большинства ее недостатков, в том числе и снижения производительности. Вместо интерпретатора языков подготовки сценариев ASP.NET использует компилируемые языки платформы .NET, такие, например, как С#, VB.NET и даже управляемый C++.
Таким образом, теперь уже можно выбирать из нескольких технологий. Это общий шлюзовой интерфейс (CGI), интерфейс прикладного программирования Internet-сервера (ISAPI), ASP и ASP.NET. Ну да, есть еще и библиотека шаблонных классов ATL. Так же, как и ASP.NET, библиотека шаблонных классов ATL дает возможность разрабатывать как Web-узлы, так и Web-службы. Впрочем, серверы и службы на основе библиотеки шаблонных классов ATL создаются с помощью библиотеки шаблонов для C++, разработанной на основе технологии ISAPI (интерфейс прикладного программирования Internet-сервера).

Приложения на основе ATL Server

ATL Server (ATL-сервер) — это технология, использующая неуправляемый C++ и позволяющая в процессе разработки эффективно и без проблем применять интерфейс прикладного программирования Internet-сервера (ISAPI)[Библиотека шаблонных классов ATL в использовании удобнее, чем традиционный интерфейс прикладного программирования Internet-сервера (ISAPI), хотя и не может сравниться по удобству с ASP NET]. Так как интерфейс прикладного программирования Internet-сервера (ISAPI) традиционно используется в тех приложениях, где основным требованием является производительность, то не удивительно, что и в ATL Server предусмотрены те же преимущества в производительности.
Библиотека шаблонных классов ATL реализована в виде обычной библиотеки шаблонных классов для C++. Шаблоны в C++ имеют замечательное свойство: они позволяют определять новые классы на основе параметров, передаваемых компилятору. Благодаря такой возможности пользователи могут эффективно и гибко пополнять библиотеку классов.
Шаблон проекта ATL Server Project (Проект на основе ATL Server) содержит код пусковой системы для динамически подключаемой библиотеки (DLL) расширения интерфейса прикладного программирования Internet-сервера (ISAPI Extension DLL), которая через информационный сервер Internet (ПЗ) получает информацию из HTTP-запросов и сопровождающей Web-приложение динамически подключаемой библиотеки (DLL). Эта сопровождающая динамически подключаемая библиотека фактически реализует все необходимые для Web-приложения функциональные возможности.
Динамически подключаемые библиотеки (DLL) расширений интерфейса прикладного программирования Internet-сервера (ISAPI) и Web-приложений работают вместе с SRF-файлами (Server Request File — файлы запросов на обслуживание). В этих файлах содержится комбинация HTML-кода и простых дескрипторов сценариев или заглушек. Каждый такой файл содержит шаблон (не путать с шаблонами C++), предназначенный для создания Web-страницы для клиента. Эти страницы создаются путем замены заглушек, расположенных внутри двойных фигурных скобок. Каждой из заглушек дается имя, указывающее на функцию, которая реализуется динамически подключаемой библиотекой (DLL) Web-приложения. А при создании Web-страницы, которую надо передать клиенту в ответ на его запрос, каждая из этих функций генерирует фрагмент HTML-кода, подставляемый вместо дескриптора в двойных фигурных скобках.
Обычно при разработке Web-приложения на основе ATL Server большая часть времени уходит на вставку кода в динамически подключаемую библиотеку (DLL) этого приложения. Впрочем, имея исходный код, можно также делать изменения и в динамически подключаемой библиотеке (DLL) расширения интерфейса прикладного программирования Internet-сервера (ISAPI) (БАР1 Extension DLL). Но это может потребоваться только в том случае, когда нужно изменить грамматический разбор SRF-файла или обеспечить ту или иную фильтрацию HTTP-потока. Такой прием используется редко и является достаточно сложным.

ATL Server основан на интерфейсе прикладного программирования Internet-сервера (ISAPI)
Чтобы разобраться в ATL Server, очень важно вначале хорошо разобраться в теоретических основах интерфейса прикладного программирования Internet-сервера (ISAPI). Динамически подключаемая библиотека (DLL) интерфейса прикладного программирования Internet-сервера (ISAPI DLL) используется для фильтрации клиентских HTTP-запросов на входе/выходе информационного сервера Internet US (фильтр интерфейса прикладного программирования Internet-сервера (ISAPI)) или для динамической генерации HTML-кода, отправляемого клиенту в ответ на его запрос (расширение интерфейса прикладного программирования Internet-сервера (ISAPI)). И фильтры, и расширения интерфейса прикладного программирования Internet-сервера (ISAPI) используются для того, чтобы изменить или расширить обычное поведение информационного сервера Internet (US). Фильтры интерфейса прикладного программирования Internet-сервера (ISAPI) прекрасно подходят, в частности, для шифрования данных, мониторинга производительности и настройки системы опознавания. Что касается расширений интерфейса прикладного программирования Internet-сервера (ISAPI), то они прекрасно подходят для динамической генерации HTML-кода и для динамического преобразования в HTML-формат данных, не являющихся HTML-кодом — в частности, записей из базы данных. Например, расширение интерфейса прикладного программирования Internet-сервера (ISAPI) может отправлять запрос в базу данных и затем помещать полученные результаты в подходящим образом отформатированную HTML-страницу.

Архитектура приложения, использующего ATL server
Как и динамически подключаемые библиотеки (DLL) традиционных расширений интерфейса прикладного программирования Internet-сервера (ISAPI), динамически подключаемые библиотеки (DLL) расширений интерфейса прикладного программирования Internet-сервера (ISAPI) на основе библиотеки шаблонных классов ATL экспортируют функции GetExtensionVersion (получить версию расширения), HttpExtension-Proc (процедура HTTP-расширения) и TerminateExtension (завершить расширение). Кроме того, следуя традиционной манере, информационный сервер Internet (IIS) создает для каждого HTTP-запроса структуру EXTENSION_CONTROL_BLOCK (управляющий блок расширения). Она в качестве параметра передается в HttpExtensionProc. Эта структура обеспечивает доступ как к информации HTTP-заголовка, так и к потокам данных. Доступ к тому и другому нужен для поддержки связи с HTTP-клиентом.
Главной точкой входа для расширения интерфейса прикладного программирования Internet-сервера (ISAPI) является функция HttpExtensionProc. Она автоматически вызывается информационным сервером Internet (П5), если нужно обработать HTTP-запрос, который предназначен для расширения интерфейса прикладного программирования Internet-сервера (ISAPI) (ISAPI Extension). Для чтения клиентских данных и соответствующего реагирования HttpExtensionProc использует функции обратного вызова, предоставляемые параметром EXTENSION_CONTROL_BLOCK. На рис. 12.1 показана общая схема использования интерфейса прикладного программирования Internet-сервера (ISAPI) в Web-приложении, основанном на ATL Server.
На рис. 12.1 показана только одна динамически подключаемая библиотека (DLL) расширения интерфейса прикладного программирования Internet-сервера (ISAPI). Это сделано потому, что в каждом виртуальном каталоге-информационного сервера Internet (IIS) может быть только одна такая библиотека. Еще ла рисунке видно, что в виртуальном каталоге может быть несколько динамически подключаемых библиотек (DLL) Web-приложения и несколько . srf-файлов. И хотя код в динамически подключаемой библиотеке (DLL) расширения интерфейса прикладного программирования Internet-сервера (ISAPI) можно настраивать, все же это обычно делается в динамически подключаемых библиотеках (DLL) Web-приложений, потому что именно в этих библиотеках реализуются обработчики запросов.

Создание проекта ATL Server Project (Проект на основе ATL Server)
Чтобы с помощью ATL Server Project Wizard (Мастер создания проектов на основе ATL Server) создать проект ATL Server Project (Проект на основе ATL Server), нужно соблюдать определенную последовательность действий. Создать свой собственный проект вы можете либо выполнив указанные ниже действия, либо открыв в каталоге ATLServerApp (приложение на основе ATL Server) имеющееся в нем решение ATLServerApp.sin [В имеющемся решении находится также дополнительный код, который будет добавляться по мере чтения следующих нескольких страниц. ].
1. Выберите следующие пункты меню: File => New => Project (Файл => Создать => Проект).
2. В дереве Project Types (Типы проектов) откройте узел Visual C++ Projects (Проекты Visual C++).
3. В окне Templates (Шаблоны) выберите ATL Server Project (Проект на основе ATL Server) [Обратите внимание, что в этом окне указан также шаблон ATL Server Web Service Project (Проект Web-службы на основе ATL Server) Выбор каждого из этих шаблонов приводит к появлению одного и того же мастера ATL Server Project Wizard (Мастер создания проектов на основе ATL Server), хотя и с небольшими отличиями. Этот мастер позволяет создать динамически подключаемую библиотеку DLL как для расширения интерфейса прикладного программирования Internet-сервера (ISAPI), так и для Web-приложения, но при выборе первого из указанных шаблонов задаются определенные значения параметров поддержки шаблона и проверки правильности Второй шаблон предназначен для создания проекта Web-службы, а не HTML-содержимого. ].
4. В качестве имени проекта введите ATLServerApp.
5. Введите имя каталога, предназначенного для хранения проекта. В данном случае используется каталог Demos (Демонстрационные примеры).
6. Для запуска Мастера создания проектов на основе ATL Server ATL Server Project Wizard щелкните на кнопке ОК.
7. Перед тем как продолжать работу с этим мастером, просмотрите на ее вкладке Overview (Общие сведения) значения параметров, заданные по умолчанию. Кроме того, посмотрите на вкладки Project Settings (Параметры проекта), Server Options (Параметры сервера), Application Options (Параметры приложения) и Developer Support Options (Параметры поддержки разработчика). Они показаны на рисунках 12.2, 12.3, 12.4, 12.5 и 12.6.
8. Не изменяя этих заданных по умолчанию значений, щелкните на кнопке Finish (Готово).
9. На рис. 12.2 показана страница Overview (Общие сведения) Мастера создания проектов на основе ATL Server (ATL Server Project Wizard). Информацию на этой вкладке можно изменить с помощью других вкладок, которые называются Project Settings (Параметры проекта), Server Options (Параметры сервера), Application Options (Параметры приложения) и Developer Support Options (Параметры поддержки разработчика)

Страница Project Settings (Параметры проекта) Мастера создания проектов на основе ATL Server (ATL Server Project Wizard) показана на рис 12.3. Как обычно, можно изменить имя и расположение генерируемого проекта Кроме того, можно указать, следует ли генерировать динамически подключаемую библиотеку (DLL) Web-приложения (флажок Generate Web application DLL (Генерировать динамически подключаемую библиотеку (DLL) Web-приложения)). Эта библиотека реализует обработчик HTTP-запросов. Еще на данной странице можно указать, должно ли решение генерировать динамически подключаемую библиотеку (DLL) расширения интерфейса прикладного программирования Internet-сервера (ISAPI) (флажок Generate ISAPI extension DLL (Генерировать динамически подключаемую библиотеку (DLL) расширения интерфейса прикладного программирования Internet-сервера (ISAPI))). В этой библиотеке будет находиться код, предназначенный для отправки HTTP-запросов обработчику, расположенному в динамически подключаемой библиотеке (DLL) Web-приложения. Вы можете решить, надо ли объединять указанные два проекта в одну динамически подключаемую библиотеку (DLL) (флажок Generate combined DLL (генерировать объединенную динамически подключаемую библиотеку (DLL))). Ну и наконец, можно указать, надо ли генерировать автоматическую поддержку размещения, чтобы при создании вашего проекта автоматически выполнялась его установка на вашем Web-сервере (флажок Deployment support (Поддержка размещения)) [Атрибуты заставляют компилятор C++ вставлять тот или иной код в объектный файл ]. При выборе этой возможности можно указать виртуальный каталог, в котором должен быть установлен проект.
Страница Server Options (Параметры сервера) Мастера создания проектов на основе ATL Server (ATL Server Project Wizard) показана на рис. 12.4. Она позволяет добавлять в динамически подключаемую библиотеку (DLL) расширения интерфейса прикладного программирования Internet-сервера (ISAPI) несколько возможностей, таких, например, как поддержка кэширования, счетчики производительности и поддержка состояния.
Страница Application Options (Параметры приложения) Мастера создания проектов на основе ATL Server из (ATL Server Project Wizard) показана на рис. 12 5. Она позволяет добавлять в динамически подключаемую библиотеку (DLL) Web-приложения несколько возможностей, таких, например, как проверка правильности параметров запроса и переменных формы, а также поддержка замены шаблонных дескрипторов. Эта страница дает также возможность указать, что проект следует создавать в виде Web-службы (флажок Create as Web Service (Создать в виде Web-службы)), а не в виде Web-узла.
Страница Developer Support Options (Параметры поддержки разработчика) Мастера создания проектов на основе ATL Server (ATL Server Project Wizard) показана на рис. 12.6. Она позволяет управлять вставкой комментариев TODO (флажок Generate TODO comments (Генерировать комментарии TODO)), генерированием использующего атрибуты кода C++ [Чтобы работала автоматическая поддержка размещения, надо установить информационный сервер Internet (IIS). ] (флажок Attributed code (Код с атрибутами)), а также поддержкой обработки утверждений пользователя и трассировки (флажок Custom assert and trace handling support (Поддержка пользовательской обработки утверждений и трассировки)).
Теперь посмотрите на код, который создан Мастером создания проектов на основе ATL Server (ATL Server Project Wizard) с использованием всех значений, установленных по умолчанию. Solution Explorer (Поиск решения) покажет, что в решении имеется два проекта. Это проекты двух динамически подключаемых библиотек (DLL) одна— для Web-приложения, а другая — для расширения интерфейса прикладного программирования Internet-сервера (ISAPI). В решении нет проекта размещения, но если взглянуть на параметры проектов, то можно увидеть, что проекты размещаются как раз во время их создания.
• ATLServerAppIsapi — проект динамически подключаемой библиотеки (DLL) расширения интерфейса прикладного программирования Internet-сервера (IS API).
• ATLServerApp — проект динамически подключаемой библиотеки (DLL) Web-приложения.

Динамически подключаемая библиотека (DLL) расширения интерфейса прикладного программирования Internet-сервера (ISAPI)
В Solution Explorer (Поиск решения) откройте узел проекта ATLServerAppIsapi. Затем откройте файл ATLServerAppIsapi.def. Обратите внимание, что этот проект экспортирует три стандартные функции из динамически подключаемой библиотеки (DLL) расширения интерфейса прикладного программирования Internet-сервера (ISAPI). Вот эти функции.
• HttpExtensionProc вызывается для каждого HTTP-запроса к расширению интерфейса прикладного программирования Internet-сервера (ISAPI).
• GetExtensionVersion вызывается; когда расширение интерфейса прикладного программирования Internet-сервера (ISAPI) загружается информационным сервером Internet (IIS).
• TerminateExtension вызывается, когда расширение интерфейса прикладного программирования Internet-сервера (ISAPI) выгружается информационным сервером Internet (IIS).
Кроме того, обратите внимание, что реализация каждой их этих функций находится в файле ATLServerAppIsapi.cpp. В каждом случае для работы с деталями просто используется объект theExtension. Типом данного объекта является ExtensionType, который определяется с помощью шаблона CIsapiExtension. Этот шаблон берет на себя всю скучную и вызывающую периодические ворчания работу, связанную с реализацией полнофункционального расширения интерфейса прикладного программирования Internet-сервера (ISAPI), в том числе и такие детали, как организация пула потоков и диспетчеризация запросов.
typedef CIsapiExtension <> ExtensionType;
// расширение ISAPI ATL Server ExtensionType theExtension;
// Делегировать экспорт ISAPI в theExtension
// extern "C"
DWORD WINAPI HttpExtensionProc (LPEXTENSION_CONTROL_
BLOCK IpECB)
{
return theExtension.HttpExtensionProc (IpECB}; }
extern "C"
BOOL WINAPI GetExtensionVersion (HSE_VERSION_INFO* pVer)
// ЛОГИЧЕСКИЙ МЕТОД
{
return theExtension.GetExtensionVersion (pVer); }
extern "C"
BOOL WINAPI TerminateExtension (DWORD dwFlags) // ЛОГИЧЕСКИЙ МЕТОД
{
return theExtension.TerminateExtension (dwFlags);
}
Структура EXTENSION_CONTROL_BLOCK, передаваемая в качестве параметра в показанную выше функцию HttpExtensionProc, содержит несколько примечательных членов. Самые важные члены этой структуры показаны в следующем определении типа. Конечно, проект ALTServerAppIsapi часто оставляют как он есть. И все же обратите внимание, что эту информацию об HTTP-запросе вполне можно использовать для выполнения нестандартной фильтрации.
typedef struct _EXTENSION_CONTROL_BLOCK {
HCONN ConnID; //in - уникальный номер от HTTP-сервера
DWORD dwHttpStatusCode; //out - состояние завершения
LPSTR IpszMethod; //in - требуемый метод
LPSTR IpszQueryString; //in - запрос информации
LPBYTE IpbData; //in - данные, посланные клиентом LPSTR IpszContentType; //in - совместимый тип данных
BOOL { WINAPI * WriteClient ) // записать ответ клиенту ( HCONN ConnID,
LPVOID Buffer, // Буфер LPDWORD IpdwBytes, DWORD dwReserved );
BOOL ( WINAPI * ReadClient ) // чтение запроса из HTTP ( HCONN ConnID, LPVOID IpvBuffer, LPDWORD IpdwSize );
} EXTENSION_CONTROL_BLOCK, *LPEXTENSION_CONTROL_BLOCK;

Динамически подключаемая библиотека (DLL) Web-приложения
Если в проекте динамически подключаемой библиотеки (DLL) Web-приложения вы откроете заголовочный файл ATLServerApp.h, то увидите определение класса CATLServerAppHandler. Атрибут request_handler (обработчик запросов) говорит о том, что класс будет открыт как обработчик запросов на основе ATL Server. Этот обработчик будет называться Default (Стандартный). В классе CATLServerAppHandler используется взятый для примера метод OnHello, имеющий атрибут tag_name (имя дескриптора), в котором указано имя Hello (Привет). Вскоре вы увидите, как эти атрибуты связаны с реальным клиентским запросом. Обратите внимание, насколько легко с помощью такого элемента данных, как m_HttpResponse (Http-ответ), отправлять клиенту данные, предназначенные для замены дескрипторов, используя для этого оператор вставки потока.
[ request_handler("Default") ] // По умолчанию class CATLServerAppHandler
{
private: // частный
// Поместить сюда частные элементы
protected: // защищенный
// Поместить здесь защищенные члены
public:
// Поместить здесь общедоступные члены
HTTP_CODE'ValidateAndExchange() {
// TODO: Put all initialization and validation ...
// TODO: Поместить весь код инициализации
// и проверки правильности...
// Установить совместимый тип
m_HttpResponse.SetContentType("text/html"); // текст/HTML
return HTTP_SUCCESS; }
protected: // защищенный
// Вот пример того, как использовать замену... [ tag_name(name="Hello") ] // Привет HTTP_CODE OnHello(void) {
m_HttpResponse « "Hello World!"; // Привет, мир!
return HTTP_SUCCESS;
}
};
// класс CATLServerAppHandler
Динамически подключаемая библиотека (DLL) Web-приложения работает вместе с .srf-файлом. На самом деле указанный файл является HTML-файлом, в котором могут находиться переменные дескрипторы данных, расположенные внутри двойных фигурных скобок. Эти дескрипторы являются заглушками, которые при обработке запроса будут заменяться процессором шаблонов библиотеки шаблонных классов ATL В каждую заглушку вставлен метод из того класса, который реализуется в динамически подключаемой библиотеке (DLL) Web-приложения.
Чтобы заглушкам в двойных скобках, находящимся в .srf-файлах, поставить в соответствие те или иные методы из динамически подключаемой библиотеки (DLL) вашего Web-приложения, в ATL Server предусмотрены необходимые для этого атрибуты. Каждый такой метод генерирует HTML-код, который должен заменять соответствующие дескрипторы заглушек из . srf -файла.
В Solution Explorer (Поиск решения) откройте узел проекта ATLServerApp, а затем откройте файл ATLServerApp.srf. Обратите внимание, что в этом файле содержатся текст и показанные внизу дескрипторы замены. Теперь сравните ATLServerApp. srf с кодом из показанного выше файла ATLServerApp.h. Вы должны заметить— класс CATLServerAppHandler помечен атрибутом request_handler как "Default" ("Стандартный"), что соответствует находящемуся внизу дескриптору обработчика, содержащему слово Default (Стандартный). Кроме того, данный дескриптор указывает имя динамически подключаемой библиотеки (DLL) Web-приложения, а именно ATLServerApp . dll. Это немаловажно, потому что в одном и том же виртуальном каталоге может находиться любое количество динамически подключаемых библиотек (DLL), относящихся к Web-приложению. В результате, для замены дескриптора этот . srf-файл будет использовать класс CATLServerAppHandler.
Кроме того, обратите внимание, что в показанном выше коде атрибут tag_name (имя дескриптора) указывает имя "Hello" ("Привет"). Данный дескриптор соответствует находящемуся внизу дескриптору из файла . srf, содержащему слово Hello (Привет). А это, в свою очередь, означает, что дескриптор Hello (Привет) будет заменен текстом, записанным выше в элемент данных m_HttpResponse с помощью метода OnHello [В одном . srf-файле для Web-приложения можно указывать больше одной динамически подключаемой библиотеки (DLL). Подробнее об этом говорится в документации по ATL Server ]. В коде пусковой системы, сгенерированном мастером, "Default" ("Стандартный") и "Hello" ("Привет") используются исключительно как примеры, которым мы можем следовать. А при добавлении своего собственного кода мы вполне можем для атрибутов обработчика запросов и атрибутов имен дескрипторов использовать какие-то другие, более значимые имена.
{{handler ATLServerApp.dll/Default}}
This is a test: {{Hello}}
({{обработчик ATLServerApp.dll/Default}}
Это - испытание: {{Привет}})

Создание и запуск проекта на основе ATL Server
Проект на основе библиотеки шаблонных классов ATL создается обычным способом. Во время создания окно вывода показывает, как происходит размещение проекта ATL-ServerApp. При этом размещении ATLServerApp. srf, ATLServerApp.dll и ATL-ServerAppIsapi.dll копируются в каталог \inetpub\wwwroot\ATLServerApp\. На рис. 12.7 показано приложение ATLServerApp сразу же после его размещения на информационном сервере Internet (IIS).
Затем можно посмотреть, что же получилось в результате Для этого следует запустить решение обычным способом в среде Visual Studio.NET или просто перейти в Web-броузере по адресу http:7/localhost/ATLServerApp/ATLServerApp.srf. Результат показан на рис. 12.8
Полезно с помощью отладчика понаблюдать, что же происходит в динамически подключаемой библиотеке (DLL) Web-приложения. Вы обнаружите, что в ATLServerAp-plsapi.dll сперва вызывается функция HttpExtensionProc с параметром EXTENSION_CONTROL_BLOCK, который содержит структуры, описанные в табл. 12.1. Содержимое этих элементов берется по адресу, определяемому унифицированным указателем информационного ресурса (URL), который указан в Web-броузере
Следующей вызывается функция ValidateAndExchange [На самом же деле для DLL_PROCESS_ATTACH следующей вызывается функция DllMain из ATLServerApp.dll При обработке Web-запросов DllMain вызывается несколько раз, и в настоящем контексте она будет игнорироваться Впрочем, обратите внимание, — этот первый вызов DllMain происходит потому, что динамически подключаемая библиотека DLL расширения интерфейса прикладного программирования Internet-сервера (1SAPI), ATLServerAppIsapi. dll, для обработки Web-запроса динамически загружает динамически подключаемую библиотеку (DLL) Web-приложения, ATLServerApp.dll ]. Она просто отправляет в HTTP-ответ, определенное значение, которое указывает тип содержимого (text/html) Кроме того, эта функция полезна тогда, когда инициализацию и проверку надо проводить перед обработкой запроса.
И, наконец, в динамически подключаемой библиотеке (DLL) Web-приложения вызывается метод OnHello класса CATLServerAppHandler. Этот метод отправляет в HTTP-ответ текст "Hello World!" ("Здравствуй, мир!"). Получившиеся в результате данные, которые передаются на броузер, можно увидеть, просматривая исходный текст HTML []. Комментарии вида <!— комментарий —> вставлены для удобства — Прим ред
<html>
<head>
</head>
<body> <!-- тело -->
This is a test: Hello World!<br>
<!-- Это - испытание: Привет, мир! -->
</body> <!-- тело -->
</html>
Обратите внимание, что в .srf-файле указан метод-обработчик Default (Стандартный) в ATLServerApp. dll, а также дескриптор Hello (Привет), который будет заменен в результате подстановки, выполняемой динамически подключаемой библиотекой (DLL) Web-приложения
{{handler ATLServerApp.dll/Default}}
This is a test. {{Hello}}
({{обработчик ATLServerApp dll/Default}}
Это - испытание: {{Привет}})
В исходном коде указанной динамически подключаемой библиотеки (DLL) ATLServerApp.dll видно, что атрибут обработчика Default (Стандартный) применяется к классу CATLServerAppHandler, в котором содержится метод OnHello с атрибутом tag_name, соответствующим дескриптору Hello (Привет) Это означает, что когда информационный сервер Internet (US) получает запрос именно на этот . srf-файл, то, чтобы текстовая строка заменяла дескриптор, т е передавалась в ответ на запрос клиента, информационный сервер Internet (US) загружает указанную динамически подключаемую библиотеку (DLL), находит названный класс и вызывает указанный метод OnHello
Таблица 12.1. Структура EXTENSION_CONTROL_BLOCK для ATLServerApp.srf
Компонент структуры Значение
IpszMethod (метод) "СЕТ" (Получить)
IpszOueryString (строка запроса) " "
IpszPathlnf о (информация о пути) "/ATLServerApp/ ATLServerApp srf"
pbData (данные) 0
[ request_handler("Default") ] // по умолчанию
class CATLServerAppHandler
{
[ tag_name(name="Hello") ] // Привет
HTTP_CODE OnHello(void)
{
m__HttpResponse « "Hello World'"; // Привет, мир!
return HTTP_SUCCESS;
}

Добавление в сервер еще одного обработчика
Обработчик запросов, сгенерированный мастером ATL Server Wizard, предназначался только для того, чтобы показать вам, как можно писать свои собственные обработчики запросов Проанализируйте следующий код Он может служить простым примером добавления новых возможностей Этот код добавлен к ATLServerApp.h [Эти возможности также добавлены к имеющемуся примеру проекта ATLServerApp]. В новом коде класс обработчика запросов отмечен как "Another" ("Другой"), а метод замены — именем дескриптора "Time" ("Время")
// Другой обработчик, который добавлен к ATLServerApp
[request_handler("Another")] // Другой
class CAnotherATLServerAppHandler
{
protected: // защищенный
[ tag_name(name="Time") ] // Время
HTTP_CODE GetTheCurrentTime(void)
{
SYSTEMTIME systemTime;
GetLocalTime(SsystemTime);
m_HttpResponse
<< system!ime.wHour << ":" << systemTime.wMinute;
return HTTP_SUCCESS;
}
};
Как добавлять эти новые возможности к серверу, показывает файл Another .srf [К имеющемуся примеру проекта ATLServerApp добавлено несколько .srf-файлов. Все добавленные файлы будут описаны на нескольких следующих страницах. ]. Если вы добавите этот файл и заново создадите проект, то данный . srf-файл автоматически разместится вместе с остальной частью сервера. При просмотре Another. srf на Web-броузере можно увидеть отображение текущего времени. Вот содержимое файла
Another.srf.
{{handler ATLServerApp.dll/Another}} {{Time}} is the current time.
({{обработчик ATLServerApp.dll/Another}} {{Время}} - текущее время.)
Результат можно увидеть, перейдя по адресу http://localhost/ATLServerApp/ Another.srf. Кроме того, он показан на рис. 12.9.

Добавление на сервер обработки управляющей структуры if-else-endif
В файле if_else_endif. srf содержится управляющая структура if-else-endif (если-иначе-конец если). Аналогичный обработчик добавляется в динамически подключаемую библиотеку (DLL) Web-приложения. Обратите внимание, что если количество секунд четное, то возвращаемым значением является HTTP_SUCCESS (success — "успех"), а если нечетное, то возвращается HTTP_S_FALSE (false — "ложь"). S в HTTP_S_FALSE означает, что на самом деле это успешный (successful) код, и никакой ошибки нет. Вероятность каждого исхода составляет 50 %. Таким образом, если клиент выполнял обновление несколько раз, то оба указанных результата будут равномерно распределены. Обратите внимание, что метод ShouldThisBeDone ("должно ли это быть сделано") на самом деле никаких HTML-данных клиенту не отправляет. Он предназначен только для того, чтобы управлять размещением текста и дескрипторов между дескрипторами if (если), else (иначе) и endif (конец если), находящимися в . srf-файле. Вот код C++ для этих новых возможностей
// Обработчик для проверки if (если), else(иначе) и endif
[request_handler("if_else_endif")]
class C_if_else_endif_ATLServerAppHandler
{
protected: // защищенный
[ tag_name(name="ShouldThisBeDone") ]
HTTP_CODE ShouldThisBeDone(void)
{
SYSTEMTIME systemTime;
GetLocalTime(&systemTime);
// возвратить HTTP_SUCCESS в 50 % случаев
if (systemTime.wSecond % 2)
return HTTP_SUCCESS;
else
return HTTP_S_FALSE;
}
};
HTTP_SUCCESS и HTTP_S_FALSE в действительности представляют соответственно значения TRUE (ИСТИНА) и FALSE (ЛОЖЬ). Если вы в своем броузере укажете if_else_endif. srf и несколько раз обновите броузер, то увидите, что эти два исхода появляются в случайном порядке. И хотя в приоре такое не встречается, между дескрипторами if (если), else (иначе) и endif можно расположить другие дескрипторы
{{handler ATLServerApp.dll/if_else_endif}}
{{if ShouldThisBeDone}}
Here is text that is displayed if ShouldThisBeDone
{{else}}
Here is text that is displayed if *not* ShouldThisBeDone
{{endif}}
Вот более русифицированная версия.
{{обработчик ATLServerApp.dll/if_else_endif}}
{{если ShouldThisBeDone}}
Вот - текст, который отображается если ShouldThisBeDone
{{иначе}}
Вот - текст, который отображается если *не* ShouldThisBeDone
{{конец если}}
Результат можно увидеть, перейдя по адресу http://localhost/ATLServerApp/ if_else_endif.srf Два возможных исхода показаны на рис. 12.10. и 12.11.

Добавление на сервер обработки управляющей структуры while-endwhile
Следующий пример показывает использование цикла с условием окончания while-endwhile в соответствующем файле while_endwhile.srf Чтобы сохранить количество выполнений цикла, был добавлен компонент данных типа int, называемый count (счетчик) Этой переменной в конструкторе класса обработчика присваивается начальное значение, равное 0, а затем при каждом обращении к ShouldThisBeDoneAgain ("должно ли это быть сделано снова") значение count увеличивается на единицу Итерация продолжается до тех пор, пока выражение count <= 10 не станет ложным Обратите внимание, что в коде C++ на самом деле цикла с условием окончания while нет, а находится он в соответствующем . srf-файле Кроме того, в классе обработчика имеется два метода замены дескрипторов GetNextNumber (Получить следующее число) и GetNextNumberSquared (Получить квадрат следующего числа) Эти методы соответствуют двум дескрипторам из . srf-файла, появляющимся в цикле с условием окончания while
// Обработчик для проверки цикла с условием
// окончания while - endwhile
[request_handler("while_endwhile")]
class C_while_endwhile_ATLServerAppHandler
{
protected: // защищенный
int count; // счетчик
C_while_endwhile_ATLServerAppHandler() : count(0) // счетчик
{
}
[ tag_name(name="ShouldThisBeDoneAgain") ]
HTTP_CODE ShouldThisBeDoneAgain(void)
{
count++; // счетчик++;
if (count <= 10) // если (счетчик <= 10)
return HTTP_SUCCESS;
else
return HTTP_S_FALSE;
}
[ tag_name(name="GetNextNumber") ]
HTTP_CODE GetNextNumber(void)
{
m_HttpResponse
<< "The square of " << count << " is "; // Квадрат
//счетчика
return HTTP_SUCCESS;
}
[ tag_name(name="GetNextNumberSquared") ]
HTTP_CODE GetNextNumberSquared(void)
{
m_HttpResponse << count*count;
return HTTP_SUCCESS;
}
};
Соответствующий файл while_endwhile.srf отображает таблицу с числами и их квадратами В примере видно, что дескрипторы могут быть вложены так, как требуется Это приводит к тому, что дескрипторы GetNextNumber и GetNextNumberSquared заменяются несколько раз [Комментарии вида <!-- комментарий --> вставлены для удобства — Прим ред.].
<html>
<BODY> <!-- ТЕЛО -->
<Р>{{handler ATLServerApp.dll/while_endwhile}}</P> <!-- обработчик -->
<р>
<TABLE> <!-- таблица -->
{{while ShouldThisBeDoneAgain}}
<TR>
<TD>{{GetNextNumber}}</TD>
<TD>{{GetNextNumberSquared}}</TD>
</TR>
{{endwhile}}
</TABLE> <!-- таблица -->
</P>
</BODY> <!-- тело -->
</html>
Результат можно увидеть, перейдя по адресу http://localhost/ATLServerApp/while_endwhile. srf. Что получается при этом переходе, показано на рис. 12.12.

Передача параметров серверному обработчику
Файл pass_parameter. srf показывает, как можно передавать параметры методу замены обработчика запросов Web-приложения (pass parameter как раз и означает "передать параметр"). Класс обработчика запросов с помощью функций грамматического разбора преобразует первоначальные параметры, указанные в . srf-файле и имеющие строковый тип (string), в тот тип данных, который требуется методу обработчика запросов. В классе обработчика запросов сигнатура такого рода функции должна выглядеть следующим образом:
HTTP_CODE parSeFunction(
IAtlMemMgr* pMemoryManager,
LPCSTR szArgumentData,
parameterType** ppArgument);
Память, используемая для хранения преобразованного параметра, должна быть размещена с помощью pMemoryManager->Allocate (memory manager — "диспетчер памяти", allocate— "разместить"). Эту память не надо освобождать явным образом, потому что в нужное время она автоматически освобождается каркасом ATL Server. Исходные строковые (типа string) данные, передаваемые через параметр, выбираются из szArgumentData (данные аргумента). Преобразованный параметр передается методу обработчика запросов и затем сохраняется с помощью ppArgument (argument— "аргумент"). Для параметра вы можете определить свой собственный тип данных с помощью какой-либо структуры или использовать типы данных, указанные ниже .
• bool (логический, булев);
• char (символ);
• unsigned char (символ без знака);
• short (короткий);
• unsigned short (короткий без знака);
• int;
• unsigned int (int без знака);
• _int64;
• unsigned_int64(_int64 без знака);
• double (с удвоенной точностью);
• float (с плавающей точкой).
Затем, как показано в следующей сигнатуре, аргумент принимается из класса обработки запросов соответствующим методом замены:
HTTP_CODE replacementMethod(
parameterType* pArgument);
Параметр pArgument должен указывать на тот тип данных, который используется в соответствующей функции грамматического разбора.
Связывать друг с другом метод замены и соответствующую ему функцию грамматического разбора можно с помощью одного из двух приемов. В соответствии с первым из них, если parameterType (тип параметра) является одним из типов, поддерживаемых для атрибута tag_name, то имя функции грамматического разбора можно пропускать, и она будет автоматически связываться с методом замены в результате учета типа.
Ну, а в соответствии со вторым приемом имя функции грамматического разбора, связываемой с методом замены, можно указывать явно в параметре parse_func (функция грамматического разбора) атрибута tag_name. Такой прием необходимо использовать тогда, когда вы с помощью какой-либо структуры определяете свой собственный тип параметра или имеются разные методы, которые принимают один и тот же тип параметра.
В следующем примере показана передача параметров из соответствующего файла pars_parameter .srf. Передача параметров выполняется с помощью первого из двух указанных приемов. В примере можно видеть, что передача параметра требует как функции грамматического разбора, так и метода замены.
Функция должна преобразовывать параметр из строкового типа в тот, который нужен (в данном примере это int) Что касается метода замены, то он должен принимать преобразованный параметр и управлять заменой дескрипторов.
// Обработчик для проверки передачи параметров
[request_handler("pass_parameter")]
class C_parameter_passing_ATLServerAppHandler
{
protected: // защищенный
// метод синтаксического анализа преобразовывает
// параметр из строки в int
HTTP_CODE parseFunction(
IAtlMemMgr* pMemoryManager,
LPCSTR szArgumentData,
int** ppArgument)
{
// распределить память для передаваемого параметра
int *pparam =
(int *)pMemoryManager->Allocate(sizeof(int) ) ;
// Распределить
// установить значение параметра, передаваемого
// методу замены *pparam = atoi(szArgumentData) ;
// передать параметр обратно через ppArgument
ppArgument = &pparam;
return HTTP_SUCCESS;
}
// метод замены принимает параметр типа int
[ tag_name(name="SquareOfParameter") ]
HTTP_CODE SquareOfParameter(int* pArgument)
{
m_HttpResponse
<< "Parameter was " // Параметр был
<< *pArgument << "<p>"
<< "Square of parameter is" // Квадрат параметра
<< *pArgument * *pArgument;
return HTTP_SUCCESS;
}
};
Квадрат параметра отображается соответствующим файлом pass_parameter.srf.
{{handler ATLServerApp.dll/pass_parameter}}
{{SquareOfParameter(10)}}
Результат можно увидеть, перейдя по адресу http://localhost/ATLServerApp/ pass_parameter.srf Что получается при этом переходе, показано на рис. 12.13.
Кроме того, из файла . srf в обработчик запросов Web-приложения можно передавать несколько параметров различных типов. Для этого надо определить структуру с элементами, которые должны соответствовать передаваемым параметрам Следующий пример демонстрирует, как из . srf-файла передаются два параметра Первый из них является числом, а второй — строкой Функция грамматического разбора выделяет указанные два параметра из одной строки и "укладывает" их в пользовательскую структуру, которая называется PARAMETER_DATA (данные параметров) Эта функция с помощью простых приемов грамматического разбора разбивает строку-параметр на лексемы и приводит тип каждого из параметров к тому типу, который должен быть у соответствующего элемента структуры Затем структура передается методу замены как один составной параметр.
Данный пример также демонстрирует, как с помощью второго приема связать функцию грамматического разбора с указанным выше методом управления заменой В соответствии с этим приемом имя метода фа мм этического разбора явно указывается с помощью параметра parse_f unc в атрибуте tag_name метода замены
// Обработчик, который принимает два параметра
[request_handler("pass_two_parameters")]
class C_pass_two_parameters_ATLServerAppHandler
{
protected: // защищенный
// пользовательская структура для того,
// чтобы сохранять преобразованные параметры
typedef struct
{
short index; // короткий индекс
char string[100]; // строка символов
} PARAMETER_DATA;
// метод синтаксического анализа преобразовывает
// два параметра из строки
HTTP_CODE parseTwoParametersFunction(
IlAtlMemMgr* pMemoryManager,
LPCSTR szArgumentData,
PARAMETER_DATA** ppArgument)
{
// распределить память для параметров,
// которые будут переданы
PARAMETER_DATA *pparams =
(PARAMETER_DATA *)pMemoryManager->Allocate(
// Распределить
sizeof(PARAMETERJDATA));
// установить параметры, которые будут
// переданы методу замен
char *szToken = strtok( // символ
(LPSTR)szArgumentData, ", "); // получить 1-й параметр
pparams->index = atoi(szToken); // сохранить 1-й параметр
szToken = strtok(NULL, "\""); // ПУСТОЙ УКАЗАТЕЛЬ -
// пропустить пробелы, символы табуляции и пустой строки
szToken = strtok(NULL, "\""); // ПУСТОЙ"УКАЗАТЕЛЬ -
// получить 2-й параметр
strcpy(pparams->string, szToken); // строка - сохранить
// 1-й параметр
// передать параметры обратно через ppArgument
ppArgument = &pparams;
return HTTP_SUCCESS;
}
// метод замены принимает два параметра в структуру
[ tag_name(name="HandleTwoParameters",
parse_func="parseTwoParametersFunction") ]
HTTP_CODE HandleTwoParameters(PARAMETER_DATA* pArgument)
{
m_HttpResponse
<< "First parameter was " // Первый параметр был
<< pArgument->index << "<p>" // индекс
<< "Second parameter was \"" // Второй параметр был
<< pArgument->stnng << "\"<p>" // строка
<< "The ASCII code for this index is "
// Код ASCII для этого индекса
<< pArgument->string[pArgument->index] ;
return HTTP_SUCCESS;
}
Результат передачи двух параметров отображается с помощью соответствующего файла pass_two_parameters. srf (pass two parameters — "передать два параметра").
{{handler ATLServerApp.dll/pass_two_parameters}}
{{HandleTwoParametersdO, "here is a bit of text")}}
Этот результат можно увидеть, перейдя по адресу http://localhost/ATLServerApp/ pass_two_parameters .srf.

 

Резюме

Web-службы позволяют создавать крупномасштабные распределенные приложения, которые могут использовать вездесущую природу Internet Эти службы строятся на основе стандартных и повсеместных протоколов, таких, как HTML, XML и SOAP, поэтому они значительно более гибки и естественны, чем построенные на основе традиционных распределенных компьютерных технолошй, таких, например, как вызов удаленных процедур (RFC — Remote Procedure Call) Библиотека шаблонных классов ATL предоставляет возможности для создания Web-служб, и благодаря своей эффективности является идеальным средством для реализации тех Web-служб, от которых требуется высокая производительность

 
На главную | Содержание | < Назад....Вперёд >
С вопросами и предложениями можно обращаться по nicivas@bk.ru. 2013 г. Яндекс.Метрика