65.9K
CodeProject 正在变化。 阅读更多。
Home

为 Boost.Application (0.4) 库创建新的应用程序模式

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.29/5 (11投票s)

2013年12月19日

CPOL

10分钟阅读

viewsIcon

23346

downloadIcon

171

如何为 Boost.Application (0.4) 库创建新的应用程序模式

引言

本文介绍了将提议的“Application”库的新版本引入 boost.org。此新版本基于“方面”概念,并标记为 0.4.x 版本。

警告!

前段时间,我写了两篇基于 0.3 版本的文章。

创建工作队列

https://codeproject.org.cn/Articles/664709/Creating-a-Work-Queue-Thread-Pool-Application-Usin

请注意,此代码的更新样本存在于库的新版本 (0.4) 的 example/uuid_client_server 文件夹中。

使用 Boost.Application 库创建 Windows 服务应用程序

https://codeproject.org.cn/Articles/662221/Create-a-Windows-Service-Application-Using-the-Boo

请注意,此代码的更新样本存在于库的新版本 (0.4) 的 example/work_queue 文件夹中。

请注意,版本 0.3 不再维护!版本 0.4 现已维护并定期接收更新。

反馈

如果您是 Boost 用户,并且使用 Boost 邮件列表,请直接在列表中提供您对该库的反馈。(如果您认为该库应该作为 boost.org 的一部分被接受,请注明。)

如果您是 CodeProject 用户,请直接在此页面上提供您对该库的反馈。

Bug

如果您发现任何错误,请发送至 re.tf@acm.org

注意

Boost.Application 尚未成为官方 Boost C++ 库。它尚未经过审查,无法从 www.boost.org 下载。此 Beta 版本可供 Boost 社区了解真实兴趣并获取改进意见。如果社区认为它有趣,则打算提交该库进行正式审查!

什么是 Boost.Application

Boost.Application 为任何希望在 Windows 或 Unix 变体(例如 Linux、MacOS)上构建系统应用程序的人提供了一个应用程序环境或起点。

Boost.Application 也允许用户扩展库功能,例如,在本文中,Apache Httpd 模块将作为“Boost 应用程序模式”构建。

Boost.Application 的一个重要概念是“方面”,由“Vicente J. Botet Escriba”提出。“方面概念”允许轻松扩展和定制库组件。

Boost.Application 提供了许多有用的即用型功能,例如:

  • 作为 Windows 服务运行应用程序
  • 作为 UNIX/POSIX 守护进程运行应用程序
  • 插件扩展系统
  • 进程(可执行文件)单实例实例化支持
  • 应用程序 SIGNAL/回调定制
  • Windows 服务设置功能
  • 应用程序模式扩展(将在本文中介绍)
  • 以及许多其他功能

Boost.Application 资源

您可以从 GitHub 此处 下载该库。

在线文档(正在建设中)可在 此处 获取。

库官方“应用程序模式”

“应用程序模式”是库提供的一种即用型功能,在此版本中,我们有两种官方应用程序模式(类型)

  • 通用应用程序:这种应用程序是常见的交互式终端/控制台应用程序。
  • 服务器应用程序:这种应用程序生成服务(Windows)或后台进程/守护进程(Unix)。

本文将介绍如何扩展库模式,它展示了如何创建一个新的简单“应用程序模式”以在 Apache Web 服务器上使用。有了这个“模式”,用户就可以用它来生成任何 Apache 内容生成器模块。

这不是官方的“库模式”,它只是一个示例,说明如何扩展库功能。所产生的模式非常简单,并没有暴露所有 Apache Httpd Server API 功能。我们只实现一个简单的“内容生成器”,它支持 HTTP GET 动词!

0. 基本设置

此库尚未成为官方 Boost.org 库,它还使用了另外两个非官方库,因此安装并不太容易。

1) 第一步是下载最新版本的 Boost 并构建它。

Boost 的构建过程也不是很方便,但提供了良好的文档,请参考 此链接

或者您可以查看 这篇好文章 以帮助构建。

2) 第二步是下载

  1. Boost.Application (https://github.com/retf/Boost.Application/zipball/master)
  2. Boost.TypeIndex (https://github.com/apolukhin/type_index/zipball/master)
  3. Boost.Singularity (https://github.com/cppmaven/Singularity/zipball/master)

您可以将它们解压到您的“c:\”或其他目录中。我们稍后将配置 Visual Studio 项目以查找这些目录!

请注意,Boost.org 正在转向 Git,因此库的文件夹结构将来可能会改变,请参考 boost.org 了解更多信息!

1. Apache HTTP Web 服务器

Apache Web 服务器是当今部署最广泛的 Web 服务器之一。本文介绍了如何使用 Boost.Application 库创建一种扩展 Apache Web 服务器的方法。

Apache 服务器由一个相对较小的核心和许多模块组成。模块通常保存在 /modules 目录中并在运行时加载。本文展示了如何为“Boost.Application”构建一种新的应用程序模式,该模式可用于生成新的“Apache 内容生成器模块”。

1.1 安装 Apache

您需要安装包含头文件的 Apache。

您可以从 此处 下载适用于 Windows 的 Apache (2.3)。

下图展示了如何安装 Apache

重要提示:本文的重点平台是 Windows,但如果您是 UNIX/LINUX 用户,可以将其适应您的平台。“Boost.Application”是多平台的,就像任何 Boost 库一样。

2. 设置 Visual Studio 项目

Visual Studio 2012 将用于构建项目,所有提供的示例仅适用于此版本。所有代码和项目均已提供;请查看页面顶部的下载链接。

2.1 为 Apache 模块创建 Visual Studio 项目骨架。

打开 Visual Studio,创建一个 Win32 项目。在“应用程序设置”中,选择“DLL 和空项目”。

2.2 在项目中,打开属性窗口并向“C/C++ -> 常规 -> 附加包含目录”添加所需的包含目录

所需的目录是

名称目录(示例)
Your Main Boost	C:\boost_1_54_0
Your Boost.Application	E:\project.boost.app.v4.4
Your Boost.TypeIndex	E:\type_index
Your Boost.Singularity	E:\singularity
Your Apache API/APR	C:\Program Files (x86)\Apache Software Foundation\Apache2.2\include

请注意,您的目录可能具有不同的名称和位置。

2.3 在项目中,再次打开属性窗口,并将 boost 库目录添加到“链接器 -> 常规 -> 附加库目录”

请注意,当您构建 boost 时,库的常见位置是:例如:C:\boost_1_54_0\stage\lib

2.4 我们需要为 Apache “链接器 -> 常规 -> 附加库目录”做些什么

2.5 在项目中,添加一个名为“main.cpp”的新源文件和一个名为“mymode.hpp”的头文件

3. Boost.Application -> 应用程序模式

如前所述,默认情况下(在此第一个版本中),Boost.Application 提供了两种即用型应用程序模式:通用和服务器应用程序模式。一般来说,用户将使用这些模式(类型)之一来构建服务器或终端应用程序。如果提供的模式无法满足用户的需求,用户需要扩展库模式。

“应用程序模式”扩展是 Boost.Application 最先进的功能,新的模式通常需要与一些第三方 API 配合使用,例如在 Windows 上,“服务器”模式封装并抽象 Windows 服务 API 给最终用户。

在我们的例子中,我们将使用(封装在新模式中)Apache API,我们将在我们的模式中使用 Apache 可移植运行时 (APR)。

在下图中,我们有“Boost.Application”组件的示意图,其中红色突出显示了我们修改/添加的部分。

有关完整参考,请参阅 此链接

4. 启动我们的应用程序模式

在“main.cpp”中,我们将编写客户端代码,在“mymode.hpp”中,我们将编写模式实现。

此时,最好您看一下路线图以了解如何制作一个简单的应用程序

http://www.dokfile.com/appbeta4/docs/libs/application/doc/html/boost_application/roadmap.html

我们将创建一个新模式,用于步骤“H”。

4.1 应用程序模式介绍

基本上,“应用程序模块”由一个“模式类”组成,该类需要具有定义的结构(构造函数和方法)和“方面”集合。

“方面”可以是任何类,但“Boost.Application”提供了一些基类,允许我们创建特殊类型的“方面”,例如回调(处理程序)方面。

要了解更多信息,请参阅 此链接

在我们的案例中,我们将有一个方面处理“Apache 日志”,一个处理“Web 应用程序名称”,一个处理“内容类型”,最后一个将是我们的处理程序,当 GET 请求到达时将调用它。

5. 我们的方面(图中的第 4 项)

在这里,我将介绍我们模式所有方面的实现。

5.1 日志方面

此方面将为最终用户提供日志功能。请看

C:\Program Files (x86)\Apache Software Foundation\Apache2.2\logs 

在这个文件夹里,我们有很多日志。我们的“日志方面”将为用户提供使用此日志的方法!

httpd.exe:无法可靠地确定服务器的完全限定域名,使用 192.168.0.9 作为 ServerName

[Wed Dec 11 09:38:05 2013] [notice] Apache/2.2.25 (Win32) configured -- resuming normal operations  

[Wed Dec 11 09:38:05 2013] [notice] Server built: Jul 10 2013 01:52:12  

[Wed Dec 11 09:38:05 2013] [notice] Parent: Created child process 6836 

[Wed Dec 11 09:38:12 2013] [warn] Page requested! Boost.Application! 
Apache 日志示例
class apache_log
{
   friend class apache2_httpd_mod;

public:
   apache_log(request_rec *r)
      : r_(r) { }

   void error(const std::string& msg)
   {
      ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, 0, r_->server, msg.c_str());
   }

   void information(const std::string& msg)
   {
      ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_INFO, 0, r_->server, msg.c_str());
   }

   void warning(const std::string& msg)
   {
      ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_WARNING, 0, r_->server, msg.c_str());
   }
private:
   request_rec *r_;

};
apache_log 方面。

5.2 Web 应用程序名称方面

此方面用于在 Apache 上识别我们的应用程序,这样 Apache 就可以知道它是否处理我们的请求。

例如:https://:8080/boostapp

boostapp”是我们的 Web 应用程序名称。

class web_app_name
{
   friend class apache2_httpd_mod;

public:
   web_app_name(const std::string& web_app_name)
      : web_app_name_ (web_app_name)
   {}

private:
   std::string web_app_name_;
};
web_app_name 方面

5.3 内容类型方面

此方面用于识别将推送到浏览器客户端的内容。

例如:“text/html;charset=ascii

class content_type
{
   friend class apache2_httpd_mod;

public:
   content_type(const std::string& my_content_type)
      : content_type_ (my_content_type)
   {}

private:
   std::string content_type_;
};
content_type 方面

5.4 GET 动词处理程序方面

此方面最为重要,它将允许我们模式的最终用户将自定义的“内容生成器”处理程序绑定到 HTTP GET 动词。

class http_get_verb_handler : public handler<std::string>
{
public:
   http_get_verb_handler(const parameter_callback& callback)
      : handler<std::string>(callback) {}

   http_get_verb_handler(const singleton_callback& callback)
      : handler<std::string>(callback) {}
};
http_get_verb_handler 方面

请注意,我们继承自“boost::application::handler<:string>”。

要了解更多关于提供的处理程序的信息,请参阅 此链接

6. 实现我们的方面(图中的第 2 项)

“应用程序模式”是一个将被“boost::application::launch”函数初始化的类。在我们的模式设计中,每个到达的请求都会启动一个新的 apache2_httpd_mod!在这里,模式设计者可以自由地做任何事情。

class apache2_httpd_mod
{

public:

   static int mode()
   {
      static int id = new_run_mode<int>();
      return id;
   }

   template <typename Application, typename RequestRec>
   apache2_httpd_mod(Application& myapp, RequestRec &rr, 
      context &cxt, boost::system::error_code& ec)
      : error_(OK) 
   {
   }

   template <typename Application, typename RequestRec>
   apache2_httpd_mod(Application& myapp, RequestRec &rr, 
      boost::singularity<context> &cxt, boost::system::error_code& ec)
      : error_(OK) 
   {
   }

   int run() { return error_; }

protected:

    // ...

};
apache2_httpd_mod 模式骨架

请注意,所有“模式”都需要遵守这些签名。

mode”方法用于识别模式,我们有两个构造函数,一个支持单例,另一个将接收“context”作为参数,以及在我们的案例中将状态码返回给客户端的“run”方法。

之后,模块设计者可以自由添加任何其他必要的方法。现在让我们开始吧

class apache2_httpd_mod
{

public:

   static int mode()
   {
      static int id = new_run_mode<int>();
      return id;
   }

   template <typename Application, typename RequestRec>
   apache2_httpd_mod(Application& myapp, RequestRec &rr, 
      context &cxt, boost::system::error_code& ec)
      : error_(OK) 
   {
      handle_request(myapp, rr, cxt);
   }

   template <typename Application, typename RequestRec>
   apache2_httpd_mod(Application& myapp, RequestRec &rr, 
      boost::singularity<context> &cxt, boost::system::error_code& ec)
      : error_(OK) 
   {
      handle_request(myapp, rr, cxt.get_global());
   }

   int run() { return error_; }

protected:

   template <typename Application, typename RequestRec>
   void handle_request(Application& myapp, RequestRec &rr, context &cxt)
   {
      // default impl aspects

      if(!cxt.find<run_mode>())
      {
         cxt.insert<run_mode>(
            csbl::make_shared<run_mode>(mode()));
      }

      if(!cxt.find<status>())
      {
         cxt.insert<status>(
            csbl::make_shared<status>(status::running));
      }

      csbl::shared_ptr<web_app_name> appname = cxt.find<web_app_name>();

      if(!appname)
      {
         error_ = DECLINED; return;
      }

      if (strcmp(rr.handler, appname->web_app_name_.c_str())) 
      {
         error_ = DECLINED; return;
      }

      // we allow only GET
      
      // Add other http verbs 
      // ...

      if(rr.method_number != M_GET)
      {
         error_ = HTTP_METHOD_NOT_ALLOWED; return;
      }
         
      // GET

      csbl::shared_ptr<http_get_verb_handler> http_get_verb =
         cxt.find<http_get_verb_handler>();
      
      if(http_get_verb)
      {
         // apache log 
         cxt.insert<apache_log>(csbl::make_shared<apache_log>(&rr));

         csbl::shared_ptr<content_type> contenttype = 
            cxt.find<content_type>();

         if(contenttype)
            ap_set_content_type(&rr, contenttype->content_type_.c_str());
         else
            ap_set_content_type(&rr, "text/html;charset=ascii");

         // check if we have any callback to call

         handler<std::string>::parameter_callback* parameter = 0;

         if(http_get_verb->callback(parameter))
         {
            ap_rputs((*parameter)(cxt).c_str(), &rr); return;
         }

         handler<std::string>::singleton_callback* singleton = 0;

         if(http_get_verb->callback(singleton))
         {
            ap_rputs((*singleton)().c_str(), &rr); return;
         }
      }

      // we need set application_state to stop
      cxt.find<status>()->state(status::stoped);

      // we cant find any handler, generate apache error
      error_ = HTTP_INTERNAL_SERVER_ERROR;
   }

private:

   int error_;

};
使用 Apache APR 的完整 apache2_httpd_mod 模式

6.1 将所有内容导出,以便 Apache 知道我们的模式

为此,我们将实现一个 MACRO,最终用户需要将其添加到“.cpp”文件中。

#define BOOST_APPLICATION_APACHE_REGISTER_TEST_MY_MODE(h, m)                   \
extern "C" {                                                                   \
void boost_application_register_hooks(apr_pool_t *p)                           \
{                                                                              \
   ap_hook_handler(h, NULL, NULL, APR_HOOK_MIDDLE);                            \
}                                                                              \
                                                                               \
module AP_MODULE_DECLARE_DATA m = {                                            \
    STANDARD20_MODULE_STUFF,                                                   \
    NULL,                                                                      \
    NULL,                                                                      \
    NULL,                                                                      \
    NULL,                                                                      \
    NULL,                                                                      \
    boost_application_register_hooks                                           \
}; }
导出宏

6.2 模式总结

现在我们的模式已可使用。现在,我们的角色不再是“模式设计者”,而是“模式用户”(客户端/最终用户)

7. 使用新“模式”

在这里,我将介绍最终/客户端用户如何使用我们的新模式。

7.1 创建一个应用程序函数对象类

在“main.cpp”中,我们将创建我们的 functor 类。

class my_apache2_httpd_content_generator_mod
{
public:

   int operator()(application::context& context) 
   {
      return 0; 
   }

   std::string get(application::context& context)
   {
      context.insert<content_type>(
         boost::make_shared<content_type>("text/html;charset=ascii"));

      std::stringstream htm;

      htm.str("");
      htm << "<html>"
          << "   <head>"
          << "      <title>Boost.Application Test</title>"
          << "   </head>"
          << ""
          << "   <body>"
          << "      <h1> Hello Boost.Application Version " 
          << application::library_version_string() << "!"
          << "      </h1>"
          << "      <br/>"
          << "      Apache HTTPd Mod."
          << "      <br/>"
          << "   </body>"
          << "</html>"
          ;

      boost::shared_ptr<apache_log> apachelog = context.find<apache_log>();
      if(apachelog)
      {
         // log something on apache log file
         apachelog->warning("Page requested!");
      }

      return htm.str();
   }
};
应用程序函数对象类

在“get”方法中,我们将生成我们的内容,在这种情况下,内容将是一个简单的 HTML 页面。我们将使用我们的“日志方面”工具!

7.2 实现“main”函数

此函数将由 Apache 在请求时调用,我们使用它在运行时设置我们的应用程序模式。

// an application will be launched to handle each request that arrives.
extern "C" int myhandle(request_rec *r)
{   
   my_apache2_httpd_content_generator_mod app;

   application::context app_context;

   app_context.insert<web_app_name>(
      boost::make_shared<web_app_name>("boostapp"));

   handler<std::string>::parameter_callback my_http_get_verb
      = boost::bind<std::string>(
         &my_apache2_httpd_content_generator_mod::get, &app, _1);

   app_context.insert<http_get_verb_handler>(
      boost::make_shared<
         http_get_verb_handler>(my_http_get_verb));

   return application::launch<apache2_httpd_mod>(app, *r, app_context);
}
我们的主函数 (myhandler)

Apache Web 服务器调用此函数,传入一个“request_rec”,我们将把它传递给我们的模式。

然后,我们创建应用程序 functor 类,即我们的上下文,它将包含我们所有的方面。要了解更多关于上下文的信息,请参阅 此链接

之后,我们使用我们刚刚创建的模式方面。请注意,我们将我们的“get”方法绑定到我们的“http_get_verb_handler”方面。

最后一步是将所有内容关联起来并运行“内容生成器”,我们使用“application::launch”函数来完成此操作”,该函数接收我们的模式作为模板参数。

7.3 注册我们的“main (myhandler)”函数

最后一步是使用我们的 MACRO 注册我们的主函数。

// register request function and mod on apache server
BOOST_APPLICATION_APACHE_REGISTER_TEST_MY_MODE(myhandle, my_boost_app_mod)
注册 myhandler

8. 配置 httpd.conf

现在是时候配置我们的“httpd.conf”文件了。

此文件位于“/conf”中,在我的情况下

C:\Program Files (x86)\Apache Software Foundation\Apache2.2\conf 

8.1 在 httpd.conf 中添加我们的模块

打开文件并添加以下内容

// file continues ...
#LoadModule version_module modules/mod_version.so
#LoadModule vhost_alias_module modules/mod_vhost_alias.so

LoadModule my_boost_app_mod "C:\Users\Renato Tegon Forti\Desktop\mymod\Debug\mymod.dll"
<Location /boostapp>
  SetHandler boostapp
</Location>
   

// file continues ...
Httpd 配置

将“C:\Users\Renato Tegon Forti\Desktop\mymod\Debug\mymod.dll”更改为您的路径。

9. 测试

转到您的 Apache 文件夹,并以管理员身份启动 Apache。

9.1 打开您的浏览器并请求页面,您应该会看到

10. 结论

在这里,我展示了用户如何扩展库,还有许多其他即用型功能可用,我非常喜欢的一个是插件系统。请查阅文档。

请发送您的评论,让我知道您是否喜欢这篇文章。此外,请随时提出建议并报告错误。

© . All rights reserved.