Apache001_ 模块介绍

Apache概述

Apache是目前世界上使用最为广泛的一种Web Server,它以跨平台、高效和稳定而闻名。按照去年官方统计的数据,Apache服务器的装机量占该市场60%以上的份额。尤其是在X(Unix/Linux)平台上,Apache是最常见的选择。其它的Web Server产品,比如IIS,只能运行在Windows平台上,是基于微软.Net架构技术的不二选择。

Apache支持许多特性,大部分通过模块扩展实现。常见的模块包括mod_auth(权限验证)、mod_ssl(SSL和TLS支持) mod_rewrite(URL重写)等。一些通用的语言也支持以Apache模块的方式与Apache集成。 如Perl,Python,Tcl,和PHP等。

Apache并不是没有缺点,它最为诟病的一点就是变得越来越重,被普遍认为是重量级的WebServer。所以,近年来又涌现出了很多轻量级的替代产品,比如lighttpd,nginx等等,这些WebServer的优点是运行效率很高,但缺点也很明显,成熟度往往要低于Apache,通常只能用于某些特定场合。

Apache组件逻辑图

Apache是基于模块化设计的,总体上看起来代码的可读性高于php的代码,它的核心代码并不多,大多数的功能都被分散到各个模块中,各个模块在系统启动的时候按需载入。你如果想要阅读Apache的源代码,建议你直接从main.c文件读起,系统最主要的处理逻辑都包含在里面。

MPM(Multi -Processing Modules,多重处理模块)是Apache的核心组件之一,Apache通过MPM来使用操作系统的资源,对进程和线程池进行管理。Apache为了能够获得最好的运行性能,针对不同的平台(Unix/Linux、Window)做了优化,为不同的平台提供了不同的MPM,用户可以根据实际情况进行选择,其中最常使用的MPM有prefork和worker两种。至于您的服务器正以哪种方式运行,取决于安装Apache过程中指定的MPM编译参数,在X系统上默认的编译参数为prefork。由于大多数的Unix都不支持真正的线程,所以采用了预派生子进程(prefork)方式,象Windows或者Solaris这些支持线程的平台,基于多进程多线程混合的worker模式是一种不错的选择。对此感兴趣的同学可以阅读有关资料,此处不再多讲。Apache中还有一个重要的组件就是APR(Apache portable Runtime Library),即Apache可移植运行库,它是一个对操作系统调用的抽象库,用来实现Apache内部组件对操作系统的使用,提高系统的可移植性。Apache对于php的解析,就是通过众多Module中的php Module来完成的。

PHP与Apache

当PHP需要在Apache服务器下运行时,一般来说,它可以mod_php5模块的形式集成, 此时mod_php5模块的作用是接收Apache传递过来的PHP文件请求,并处理这些请求, 然后将处理后的结果返回给Apache。如果我们在Apache启动前在其配置文件中配置好了PHP模块(mod_php5), PHP模块通过注册apache2的ap_hook_post_config挂钩,在Apache启动的时候启动此模块以接受PHP文件的请求。

除了这种启动时的加载方式,Apache的模块可以在运行的时候动态装载, 这意味着对服务器可以进行功能扩展而不需要重新对源代码进行编译,甚至根本不需要停止服务器。 我们所需要做的仅仅是给服务器发送信号HUP或者AP_SIG_GRACEFUL通知服务器重新载入模块。 但是在动态加载之前,我们需要将模块编译成为动态链接库。此时的动态加载就是加载动态链接库。 Apache中对动态链接库的处理是通过模块mod_so来完成的,因此mod_so模块不能被动态加载, 它只能被静态编译进Apache的核心。这意味着它是随着Apache一起启动的。

Apache是如何加载模块的呢?我们以前面提到的mod_php5模块为例。 首先我们需要在Apache的配置文件httpd.conf中添加一行:

1 LoadModule php5_module modules/mod_php5.so

这里我们使用了LoadModule命令,该命令的第一个参数是模块的名称,名称可以在模块实现的源码中找到。 第二个选项是该模块所处的路径。如果需要在服务器运行时加载模块, 可以通过发送信号HUP或者AP_SIG_GRACEFUL给服务器,一旦接受到该信号,Apache将重新装载模块, 而不需要重新启动服务器。

在配置文件中添加了所上所示的指令后,Apache在加载模块时会根据模块名查找模块并加载, 对于每一个模块,Apache必须保证其文件名是以“mod_”开始的,如PHP的mod_php5.c。 如果命名格式不对,Apache将认为此模块不合法。Apache的每一个模块都是以module结构体的形式存在, module结构的name属性在最后是通过宏STANDARD20_MODULE_STUFF以__FILE__体现。 关于这点可以在后面介绍mod_php5模块时有看到。这也就决定了我们的文件名和模块名是相同的。 通过之前指令中指定的路径找到相关的动态链接库文件后,Apache通过内部的函数获取动态链接库中的内容, 并将模块的内容加载到内存中的指定变量中。

在真正激活模块之前,Apache会检查所加载的模块是否为真正的Apache模块, 这个检测是通过检查module结构体中的magic字段实现的。 而magic字段是通过宏STANDARD20_MODULE_STUFF体现,在这个宏中magic的值为MODULE_MAGIC_COOKIE, MODULE_MAGIC_COOKIE定义如下:

1 #define MODULE_MAGIC_COOKIE 0x41503232UL /* "AP22" */

最后Apache会调用相关函数(ap_add_loaded_module)将模块激活, 此处的激活就是将模块放入相应的链表中(ap_top_modules链表: ap_top_modules链表用来保存Apache中所有的被激活的模块,包括默认的激活模块和激活的第三方模块。)

Apache对PHP的支持是通过Apache的模块mod_php5来支持的。如果希望Apache支持PHP的话,在./configure步骤需要指定--with-apxs2=/usr/local/apache2/bin/apxs 表示告诉编译器通过Apache的mod_php5/apxs来提供对PHP5的解析。

在最后一步make install的时候我们会看到将动态链接库libphp5.so(Apache模块)拷贝到apache2的安装目录的modules目录下,并且还需要在httpd.conf配置文件中添加LoadModule语句来动态将libphp5.so 模块加载进来,从而实现Apache对php的支持。

由于该模式实在太经典了,因此这里关于安装部分不准备详述了,相对来说比较简单。我们知道nginx一般包括两个用途HTTP Server和Reverse Proxy Server(反向代理服务器)。在前端可以部署nginx作为reverse proxy server,后端布置多个Apache来实现机群系统server cluster架构的。

因此,实际生产中,我们仍旧能够保留Apache+mod_php5的经典App Server,而仅仅使用nginx来当做前端的reverse proxy server来实现代理和负载均衡。 因此,建议nginx(1个或者多个)+多个apache的架构继续使用下去。

Apache2的mod_php5模块包括sapi/apache2handler和sapi/apache2filter两个目录 在apache2_handle/mod_php5.c文件中,模块定义的相关代码如下:

01 AP_MODULE_DECLARE_DATA module php5_module = {
02     STANDARD20_MODULE_STUFF,
03         /* 宏,包括版本,小版本,模块索引,模块名,下一个模块指针等信息,其中模块名以__FILE__体现 */
04     create_php_config,      /* create per-directory config structure */
05     merge_php_config,       /* merge per-directory config structures */
06     NULL,                   /* create per-server config structure */
07     NULL,                   /* merge per-server config structures */
08     php_dir_cmds,           /* 模块定义的所有的指令 */
09     php_ap2_register_hook
10         /* 注册钩子,此函数通过ap_hoo_开头的函数在一次请求处理过程中对于指定的步骤注册钩子 */
11 };

它所对应的是Apache的module结构,module的结构定义如下:

01 typedef struct module_struct module;
02 struct module_struct {
03     int version;
04     int minor_version;
05     int module_index;
06     const char *name;
07     void *dynamic_load_handle;
08     struct module_struct *next;
09     unsigned long magic;
10     void (*rewrite_args) (process_rec *process);
11     void *(*create_dir_config) (apr_pool_t *p, char *dir);
12     void *(*merge_dir_config) (apr_pool_t *p, void *base_conf, void*new_conf);
13     void *(*create_server_config) (apr_pool_t *p, server_rec *s);
14     void *(*merge_server_config) (apr_pool_t *p, void *base_conf, void*new_conf);
15     const command_rec *cmds;
16     void (*register_hooks) (apr_pool_t *p);
17 }

上面的模块结构与我们在mod_php5.c中所看到的结构有一点不同,这是由于STANDARD20_MODULE_STUFF的原因, 这个宏它包含了前面8个字段的定义。STANDARD20_MODULE_STUFF宏的定义如下:

1 /** Use this in all standard modules */
2 #define STANDARD20_MODULE_STUFF MODULE_MAGIC_NUMBER_MAJOR, \
3                 MODULE_MAGIC_NUMBER_MINOR, \
4                 -1, \
5                 __FILE__, \
6                 NULL, \
7                 NULL, \
8                 MODULE_MAGIC_COOKIE, \
9                                 NULL      /* rewrite args spot */

在php5_module定义的结构中,php_dir_cmds是模块定义的所有的指令集合,其定义的内容如下:

01 const command_rec php_dir_cmds[] =
02 {
03     AP_INIT_TAKE2("php_value", php_apache_value_handler, NULL,
04         OR_OPTIONS, "PHP Value Modifier"),
05     AP_INIT_TAKE2("php_flag", php_apache_flag_handler, NULL,
06         OR_OPTIONS, "PHP Flag Modifier"),
07     AP_INIT_TAKE2("php_admin_value", php_apache_admin_value_handler,
08         NULL, ACCESS_CONF|RSRC_CONF, "PHP Value Modifier (Admin)"),
09     AP_INIT_TAKE2("php_admin_flag", php_apache_admin_flag_handler,
10         NULL, ACCESS_CONF|RSRC_CONF, "PHP Flag Modifier (Admin)"),
11     AP_INIT_TAKE1("PHPINIDir", php_apache_phpini_set, NULL,
12         RSRC_CONF, "Directory containing the php.ini file"),
13     {NULL}
14 };

这是mod_php5模块定义的指令表。它实际上是一个command_rec结构的数组。 当Apache遇到指令的时候将逐一遍历各个模块中的指令表,查找是否有哪个模块能够处理该指令, 如果找到,则调用相应的处理函数,如果所有指令表中的模块都不能处理该指令,那么将报错。 如上可见,mod_php5模块仅提供php_value等5个指令。

php_ap2_register_hook函数的定义如下:

1 void php_ap2_register_hook(apr_pool_t *p)
2 {
3     ap_hook_pre_config(php_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
4     ap_hook_post_config(php_apache_server_startup, NULL, NULL, APR_HOOK_MIDDLE);
5     ap_hook_handler(php_handler, NULL, NULL, APR_HOOK_MIDDLE);
6     ap_hook_child_init(php_apache_child_init, NULL, NULL, APR_HOOK_MIDDLE);
7 }

以上代码声明了pre_config,post_config,handler和child_init 4个挂钩以及对应的处理函数。 其中pre_config,post_config,child_init是启动挂钩,它们在服务器启动时调用。 handler挂钩是请求挂钩,它在服务器处理请求时调用。其中在post_config挂钩中启动php。 它通过php_apache_server_startup函数实现。php_apache_server_startup函数通过调用sapi_startup启动sapi, 并通过调用php_apache2_startup来注册sapi module struct(此结构在本节开头中有说明), 最后调用php_module_startup来初始化PHP, 其中又会初始化ZEND引擎,以及填充zend_module_struct中 的treat_data成员(通过php_startup_sapi_content_types)等。

到这里,我们知道了Apache加载mod_php5模块的整个过程,可是这个过程与我们的SAPI有什么关系呢? mod_php5也定义了属于Apache的sapi_module_struct结构:

01 static sapi_module_struct apache2_sapi_module = {
02 "apache2handler",
03 "Apache 2.0 Handler",
04   
05 php_apache2_startup,                /* startup */
06 php_module_shutdown_wrapper,            /* shutdown */
07   
08 NULL,                       /* activate */
09 NULL,                       /* deactivate */
10   
11 php_apache_sapi_ub_write,           /* unbuffered write */
12 php_apache_sapi_flush,              /* flush */
13 php_apache_sapi_get_stat,           /* get uid */
14 php_apache_sapi_getenv,             /* getenv */
15   
16 php_error,                  /* error handler */
17   
18 php_apache_sapi_header_handler,         /* header handler */
19 php_apache_sapi_send_headers,           /* send headers handler */
20 NULL,                       /* send header handler */
21   
22 php_apache_sapi_read_post,          /* read POST data */
23 php_apache_sapi_read_cookies,           /* read Cookies */
24   
25 php_apache_sapi_register_variables,
26 php_apache_sapi_log_message,            /* Log message */
27 php_apache_sapi_get_request_time,       /* Request Time */
28 NULL,                       /* Child Terminate */
29   
30 STANDARD_SAPI_MODULE_PROPERTIES
31 };

这些方法都专属于Apache服务器。以读取cookie为例,当我们在Apache服务器环境下,在PHP中调用读取Cookie时, 最终获取的数据的位置是在激活SAPI时。它所调用的方法是read_cookies。

1 SG(request_info).cookie_data = sapi_module.read_cookies(TSRMLS_C);

对于每一个服务器在加载时,我们都指定了sapi_module,而Apache的sapi_module是apache2_sapi_module。 其中对应read_cookies方法的是php_apache_sapi_read_cookies函数。 这也是定义SAPI结构的理由:统一接口,面向接口的编程,具有更好的扩展性和适应性。

时间: 2024-11-03 04:08:01

Apache001_ 模块介绍的相关文章

apache常用模块介绍

mod_actions 基于媒体类型或请求方法,为执行CGI脚本而提供 mod_alias 提供从文件系统的不同部分到文档树的映射和URL重定向 mod_asis 发送自己包含HTTP头内容的文件 mod_auth_basic 使用基本认证 mod_auth_digest 使用MD5摘要认证(更安全,但是只有最新的浏览器才支持) mod_authn_alias 基于实际认证支持者创建扩展的认证支持者,并为它起一个别名以便于引用 mod_authn_anon 提供匿名用户认证支持 mod_auth

永久免费OA办公系统的功能模块介绍(一)

永久免费OA办公系统的功能模块介绍(一) 在免费OA系统的市场上,点晴OA系统可以说是免费OA系统中的佼佼者,因为点晴OA系统是真正永久免费OA办公系统,真正做到功能模块为大部分企业管理的需求,现在也越来越多的企业选择点晴OA系统.有很多免费OA用户都想知道点晴OA系统的模块有哪些?现在就让小编一一跟你们做介绍. 点晴OA系统的功能模块主要分成几个大模块:桌面.业务管理.EMAIL.知识管理.网盘.论坛.公共服务.设置.帮助.现在小编就先跟大家介绍桌面上的功能菜单. 工作日志管理:企业员工可以在

永久免费OA办公系统的功能模块介绍(三)

永久免费OA办公系统的功能模块介绍(三) 市场上有很多免费OA办公系统给企业选择,但是真正永久免费OA系统只有点晴OA办公系统,而且功能可以满足各行各业的大部分需求,提供免费的客服咨询和免费系统升级.上次小编介绍了点晴OA系统中的桌面和业务管理模块的功能,现在就来介绍Email和知识管理功能. Email:本系统内置的企业邮局(Email)完美的实现了企业内外网邮件的互联互通,管理员可以根据企业的实际需求设置系统用户只能使用内部Email或启用外部Email.或者完全禁用Email.系统内所有功

HTTP 模块介绍

  HTTP 模块介绍 HTTP 模块是一个在每次针对应用程序发出请求时调用的程序集.HTTP 模块作为 ASP.NET 请求管线的一部分调用,它们能够在整个请求过程中访问寿命周期事件.因此,HTTP 模块使您有机会检查传入的请求并根据该请求采取操作.它们还使您有机会检查出站响应并修改它. ASP.NET HTTP 模块针对所有的请求运行,这与 ISAPI 筛选器类似.但是它们是用托管代码编写的,而且可以与 ASP.NET 应用程序的生命周期完全集成. HTTP 模块典型的用法包括: ·    

Drupal标签模块介绍

Drupal 的核心模块是http://www.aliyun.com/zixun/aggregation/33847.html">Drupal 最重要的组成部分,它们是Drupal 主要功能的承载.Drupal 自带有33个模块,基本上涵盖了当前网站所应具有的全部功能:用户管理.博客.论坛.评论.相册以及日志管理的,还有新闻聚合等Web 2.0 特性的功能.这些模块都是Drupal 的下载包中所附带的.有些被开启,有些没有被开启,当需要使用一个功能的时候,先看看Drupal的核心模块是否具

Linux系统Apache服务的信息查看模块介绍

本文我们将讨论使用 mod_status 和 mod_info to 来告诉你目前服务器的工作情况我可以得到什么样的信息? 使用 mod_status,你可以知道谁在你的服务器上看些什么东西,以及有多少人连在Web 服务器上.还有其他可能你的客户不关心的信息,但是对于你,一个站点管理员来说,却是十分有用的信息. 客户喜欢这些资料我不知道你的客户都是怎样的人物,但是我的客户喜欢我提供的信息.每天一次的信息还不够,因为到一天结束时才知道就太晚了.所以他们喜欢知道现在正在发生的事情. mod_info

Python中的struct模块介绍

  这篇文章主要介绍了Python中的struct模块,代码基于Python2.x版本,需要的朋友可以参考下 准确地讲,Python没有专门处理字节的数据类型.但由于str既是字符串,又可以表示字节,所以,字节数组=str.而在C语言中,我们可以很方便地用struct.union来处理字节,以及字节和int,float的转换. 在Python中,比方说要把一个32位无符号整数变成字节,也就是4个长度的str,你得配合位运算符这么写: ? 1 2 3 4 5 6 7 8 >>> n = 1

mysql SQL Layer各个模块介绍

下面就是mysql 的逻辑架构,sql layer主要负责如下功能:权限判断.sql解析.执行计划优化.query cache的处理等操作,这些操作都是在数据库系统处理底层数据之前的工作: Storage Engine Layer主要负责底层数据存取的实现,由多种存储引擎共同组成. SQL Layer 中包含了多个子模块,下面我将逐个做一下简单的介绍: 结构图如下: 1.初始化模块顾名思议,初始化模块就是在MySQL Server 启动的时候,对整个系统做各种各样的初始化操作,比如各种buffe

apache的MPM模块介绍

一.MPM模块简介 多路处理模块,Multi-Processing Modules,MPM.负责绑定本机网络端口.接受请求,并调度子进程来处理请求. 二.MPM模块的类型 prefork 一个非线程型的.预派生的MPM worker 线程型的MPM,实现了一个混合的多线程多处理MPM,允许一个子进程中包含多个线程. event 一个标准workerMPM的实验性变种 mpm_winnt 用于Windows NT/windows 2000/Windows XP/windows 2003 系列的MP