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

C++ 编写 Apache 2.x 模块 (第一部分)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.85/5 (9投票s)

2012 年 11 月 10 日

CPOL

7分钟阅读

viewsIcon

46864

第一部分 - 设置与入门

引言

有许多资源描述了如何用 C (以及 Perl 的 mod_perl) 来构建 Apache 模块,但用 C++ 来构建的却很少。本文旨在解决这个问题,并介绍如何使用 C++ 构建一个 Apache 模块应用程序。

此时必须说明的是,C 是不可避免的。Apache 和 APR 都是用 C 编写的,我们也需要用 C 来与之接口。这里的重点是将 C 封装起来,让我们实际的应用程序完全用 C++ 来编写。

开发环境

与所有项目一样,你必须从某个地方开始。所以,让我们花些时间来完成所有设置。首先,这些文章主要面向 *nix 用户(Linux、FreeBSD 等)。如果你是 Microsoft Windows 用户,会有足够的信息让你上手,但前提是你已经是一名经验丰富的 Microsoft 开发人员。这里描述的所有内容都基于我的开发系统,该系统基于 CentOS 6。

在我自己的设置中,我有一个运行 CentOS 6 的专用服务器,但你也可以使用虚拟机。CentOS 6 服务器还安装了 X-Window。 对于实际开发,我使用一台运行 Microsoft Windows 7 的笔记本电脑。我安装了 Putty 和 Xming,这使得我可以直接在 Windows 桌面上打开各种工具。然而,*nix 纯粹主义者可以根据自己的喜好使用单个机器。

首先,我们需要确保服务器已配置好所有必需的软件包。在 CentOS 6 上,我使用 yum 安装了以下软件包:

  • yum groupinstall 'Development Tools'
  • httpd-2.2.15-15.el6.centos.1.x86_64
  • httpd-devel-2.2.15-15.el6.centos.1.x86_64
  • httpd-tools-2.2.15-15.el6.centos.1.x86_64

注意 - 如果你使用的是 32 位机器,请确保加载正确的 32 位软件包。

接下来,从 http://netbeams.org 下载并安装 Netbeans for C/C++ 到你的服务器。你可能还需要安装 Java Runtime 包,因为 Netbeans 使用它。

如果你直接在服务器上运行,现在应该可以打开 Netbeans。但是,如果你和我一样,使用的是 Microsoft Windows,那么你需要安装 Putty 和 Xming。我设置 Putty 以允许 X-Forwarding。一旦通过 SSH 连接到你的服务器,运行 Netbeans 应该会在一个漂亮的 Xming 窗口中将 IDE 显示在你的 Microsoft Windows 桌面上。

此时,你可以创建一个标准的 helloworld.c 项目来测试你的工具链,并确保一切正常。

我们的第一个 Apache 模块,HelloWorld

如果你是 Apache 模块开发新手,那么阅读标准的 Apache helloworld [1] 是一个不错的起点。你应该花几分钟时间熟悉这个教程,因为它就是我们将要用 C/C++ 格式实现的。记住,我们无法摆脱 C,但我们可以很好地将其封装在对象中。所以,在你浏览完 Apache 教程后,请回到这里,我们将开始。

[1]https://httpd.apache.ac.cn/docs/2.4/developer/modguide.html

那么,让我们开始创建我们的 Netbeans 项目。首先,从 **File > New Project** 开始,选择 **C/C++**,项目类型应为 **C/C++ Dynamic Library**,如下图所示:

在下一个屏幕中,我输入“mod_foo”作为项目名称,而不是“helloworld”,因为我将在未来的文章中使用这个项目。

现在我们有了一个准备开始的空项目。但首先,我们需要设置一些项目首选项,然后构建一个合理的文件系统布局。首先,布局:

假设你身处自己的工作目录,切换到你的项目目录:

  • cd NetBeansProjects/mod_foo
  • mkdir src
  • mkdir include

你的布局应该是这样的:

现在,右键单击你的项目,在上下文菜单底部选择 Properties。选择“Linker”,然后选择“Output”。Netbeans 默认使用的名称是“libmod_foo”,我们想将其更改为“mod_foo”,如下图所示:

接下来选择 C Compiler,在 Include Directories 中输入以下内容:

  • include [参见下面的注 1]
  • /usr/include/httpd
  • /usr/include/apr-l
  • /usr/local/include
  • /usr/include

[1] 注意,这被添加为一个“相对”包含,你选择上面创建的目录。其余的都是系统目录,应该在你的服务器上是标准的。这里有一张图展示了这些添加:

到目前为止一切顺利,但请注意,到目前为止我们配置的是“Debug (active)”构建配置。当需要构建 Release 版本时,你必须重复此操作,并为 Release 构建配置添加属性。

细心的读者会注意到,我在图片中是以 root 用户登录的,而不是我的普通账户。主要原因是在后面你会看到这确实会让调试更容易。但这里要小心,在开发系统上使用 root 账户存在安全隐患。确保你的开发系统位于防火墙后面,并且在物理上也是安全的(是的,在我去洗手间的时候,我的老板就把我所有的屏幕都反转了,只是为了证明这一点!)。

在我们开始编写代码之前,有一件事我们应该在 Netbeans 项目中做。我们将创建类对象来封装 Apache 和 APR 接口。为了组织你的项目并使其更清晰,我们将使用 Netbeans 的“logical”文件夹来创建一个“Apache”目录。在这里,我们将放置所有与 Apache 交互的对象。我们在“Source Files”和“Header Files”中都这样做。我还为 Application 添加了逻辑文件夹,以将纯 C++ 应用程序代码与 Apache 封装代码分开。请看以下图片了解更多详情:

现在是时候创建前两个文件了,mod_foo.cpp 和 mod_foo.hpp,它们应该在 Source Files 和 Header Files 的“root”文件夹中创建。请确保指定“Folder”(我们之前创建的 src 或 include):

最后,我们应该得到类似这样的结果:

我们现在可以开始构建 Apache 的“样板”代码,并添加一些其他内容以使 C++ 链接正常工作。

这是两个文件:

mod_foo.hpp

/* 
 * File:   mod_foo.hpp
 * Author: root
 *
 */

#ifndef MOD_FOO_HPP
#define MOD_FOO_HPP

#ifdef __cplusplus
#define EXTERN_C_BLOCK_BEGIN    extern "C" {
#define EXTERN_C_BLOCK_END      }
#define EXTERN_C_FUNC           extern "C"
#else
#define EXTERN_C_BLOCK_BEGIN
#define EXTERN_C_BLOCK_END
#define EXTERN_C_FUNC
#endif

#include <httpd.h>
#include <http_protocol.h>
#include <http_config.h>

#endif	/* MOD_FOO_HPP */

mod_foo.cpp

#include "mod_foo.hpp"

EXTERN_C_FUNC
int foo_handler( request_rec* inpRequest )
{
    int nReturnVal = DECLINED;
	
    if ( inpRequest->handler != NULL && strcmp( inpRequest->handler, "foo" ) == 0 )
    {
        ap_rputs( "Hello World from FOO", inpRequest );
        nReturnVal = OK;
    }

    return nReturnVal;
}

EXTERN_C_FUNC
void foo_hooks( apr_pool_t* inpPool )
{
    ap_hook_handler( foo_handler, NULL, NULL, APR_HOOK_MIDDLE );
}

EXTERN_C_BLOCK_BEGIN
module AP_MODULE_DECLARE_DATA foo_module =
{
    STANDARD20_MODULE_STUFF,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    foo_hooks
};
EXTERN_C_BLOCK_END

因此,在 Netbeans 中,我们可以通过按 F11 来构建它,如果一切顺利,你将获得成功的构建。现在是时候安装你的模块并进行第一次测试运行了。

在你的 ssh shell 中,切换到 Netbeans 构建模块的目录。在我的服务器上,它在这里:

  • ~/NetBeansProjects/mod_foo/dist/Debug/GNU-Linux-x86/

在那里你应该会看到一个 mod_foo.so 文件,我们可以将其安装到 Apache 中。注意,如果你的 ssh shell 不是 root,你需要 root 权限才能执行此操作:

  • # apxs –n foo –I mod_foo.so

Apache 的 apxs 工具应该已作为 Apache 安装的一部分安装。对于标准的 64 位服务器,这会将 mod_foo.so 安装到 /usr/lib64/httpd/modules/

现在模块已经就位,我们需要激活它。在 /etc/httpd/conf.d 中创建一个名为 foo.conf 的新文件,并在其中放入:

LoadModule foo_module modules/mod_foo.so
<Location /foo>
    SetHandler foo
</Location /foo>

最后,以 **httpd –X** 模式运行 Apache(单进程/非线程模式),这将使 Apache 运行,直到你用 Ctrl-C 终止它,然后用你喜欢的 Firefox 浏览器访问 <a href="https:///foo">https:///foo</a>。如果一切正常,你应该会看到“**Hello World from FOO”被打印出来。

调试

在我们继续编写漂亮的 OOPs 代码之前,值得一提的是如何使用 Netbeans 中集成的 gdb 调试器。显然,我们在命令行中调用了 **httpd –X**。我们不打算在 Netbeans 中构建整个 Apache 并从那里运行它(尽管你可以这样做)。

最简单的方法是使用 Debug 菜单下的 Netbeans “Attach to process”。在弹出的对话框中,输入“httpd –X”进行过滤,你将看到你从命令行启动的进程。选择它并附加。然后你可以在 foo_handler() 函数中设置一个断点。当你刷新 Firefox 时,它会在那个点中断。

但是,对于你所做的每一个代码更改,你都需要重新编译/构建,按 Ctrl-C 终止 httpd –X,使用 apxs 重新安装 mod_foo.so,重启 httpd –X,并重新附加。这听起来似乎很多,但你很快就会习惯它,并且每次迭代只需几秒钟。

总结

第一部分到此结束,所有内容都围绕着设置。在本系列的第二部分中,我们将开始将这个基本起点转化为漂亮的 C++ OOPs 风格编码技巧。

© . All rights reserved.