apache模块化体系结构简析.docx
- 文档编号:28532795
- 上传时间:2023-07-18
- 格式:DOCX
- 页数:18
- 大小:326.26KB
apache模块化体系结构简析.docx
《apache模块化体系结构简析.docx》由会员分享,可在线阅读,更多相关《apache模块化体系结构简析.docx(18页珍藏版)》请在冰豆网上搜索。
apache模块化体系结构简析
apache模块化体系结构简析
APACHE勺体系结构概述1
APACH核心功能层3
APACH核心组件4
APACH核心处理框架4
APACH可选功能层(模块)5
挂钩(HOOK6
预定义标准挂钩6
挂钩使用6
挂钩声明6
挂钩数组声明7
挂钩结构7
挂钩注册8
挂钩使用8
APACHE2.0系列的模块结构9
模块与核心的交互11
APACHE勺体系结构概述
APACH采用了分层与模块化的体系结构,如图1所示。
图1Apache分层与模块化体系结构
加上操作系统层,整个Apache可以被分隔为五层,各层次的功能如下:
(1)操作系统支持层,操作系统本身提供的底层功能,比如进程和线程、进程和线程间的通信、网络套接字通信、文件操作等。
(2)可移植运行库层,不同的操作系统提供的底层API存在着很大的差异。
对于Apache设计者而言,除了考虑WW和服务器功能的实现之外,还必须考虑不同操作系统的API细节问题。
显然,合理的做法就是将不同操作系统的底层细节封装起来形成操作系统API的适配并将其隐藏起来。
从Apache2.0开始,Apache就将专门封装不同操作系统API的任务独立出来形成一个
新的项目APR全称为Apache可移植运行库(ApachePortableRuntime,APR。
APR的任务就是屏蔽底层的操作系统API细节,对于所有的操作系统,提供一个完全相同的函数接口。
这样,Apache开发者就不必顾虑操作系统细节,而只要开发上层功能即可。
比如对于进程
不同的操作系统提供的创建进程的API是不同的,Unix下通用的是fork(),Windows
下则是CreateProcess(),OS/2、Netware及BeOS中的API也迥然不同。
APR将所有的创建细节封装起来,提供了统一的对外接口apr_proc_create()。
这样,APR的使用者如果要创
建进程,则只须调用aprproccreate(),不管它将要运行于哪个操作系统平台。
APR的独立带来的另一个潜在的益处就是它将最终形成一个独立的可移植运行库。
因此,
实际上任何应用程序如果要考虑跨平台,都可以使用它作为底层的支持。
(3)核心功能层,包括两大部分:
Apache核心程序和Apache核心模块。
Apache的核心程序主要用于实现Apache作为HTTP服务器的基本功能,这些基本功能包括:
启动和停止Apache,处理配置文件(config.c),接受和处理HTTP连接,读取HTTP请求并对该请求进行处理,处理HTTP协议。
核心模块,Apache中大部分模块都是可选择的,这意味着对于Apache而言是可有可无
的。
这些模块的缺失至多影响Apache功能的完整性,并不影响运行,比如mod_ssl、mod_alias
等。
但是有两个模块则是必需的,即mod_core和mod_so。
前者负责处理配置文件中的大部
分配置指令,并根据这些指令运行Apache,而后者则负责动态加载其余的模块,缺少了该
模块,其余的模块就无法使用。
这两个模块都必须静态编译。
对于Apache而言,另外一个重要的模块就是MPM即多进程处理模块。
尽管MPM也是
属于可选择的,但是它通常负责处理Apache中的并发模型,或者是Prefork,或者是线程
池(ThreadPool),或者是Worker模型等。
大多数情况下,它们总是会被加载,因此我们也将其视为核心的模块。
Apache核心(第三层)主要有以下两个作用。
基本的HTTP服务功能,Apache核心必须提供最基本的资源处理,或者通过文件描述符,
或者通过内存段等来提供;维护多进程运行模型;在配置好的虚拟主机上侦听TCP/IP套接
字;将接收到的客户端请求传递给特定的处理进程,处理HTTP协议状态,提供基本的读入
和写入缓冲区等。
另外,核心部分还提供一些通用的功能,比如URL及MIME头部解析,DSO
模块加载等。
ApacheModuleAPI,Apache最基本的核心功能由Apache核心完成,除此之外,核心无法提供的功能则全部由模块提供。
为了允许这些模块能够完全控制Apache的处理,
Apache核心必须提供对应的API。
在Apache中,这些API是指每个模块中包含一系列的函数(核心在处理HTTP请求的时候用来将消息传递给模块),以及一系列的以"apr"开始的函
数。
(4)可选功能层,可选功能层通常指Apache模块。
按需载入,比如,如果需要Apache服务器支持安全套接字层(SecureSocketLayer,SSL),那么毫无疑问,我们必须将mod_ssl模块加载到核心中。
目前,Apache中的模块很多,Apache能够支持的完整的注册过的模块信息可以在http:
//modules.apache.org上查看。
(5)第三方支持库,在Apache的一些模块中会使用到第三方的开发库,比如mod_ssl就使用了OpenSSLmod_perl则使用了Perl开发库。
这些第三方支持库虽然被Apache使用,但严格来说它们并不属于Apache的一部分。
APACHE体系结构的模块化特点主要体现在第三层(核心功能层)与第四层(可选功能层),Apache采用的模块化的体系结构,使它作为一个HTTP服务器的大部分功能都被分割
为相互独立的模块,这样,通过增加或删除模块就可以扩展和修改Apache提供的功能。
APACHE核心功能层
APACHES心功能层实现了APAPCH作为一个HTTP服务器应具备的基本功能,包括:
启动和停止Apache,处理配置文件,接受和处理HTTP连接,读取HTTP请求并对该请求进行
处理,处理HTTP协议等。
APACHE核心组件
从实现这些基本功能的源代码来看,Apache的核心功能层可以有以下的几个组件组成:
配置文件组件(HTTP_CONFI)进程并发处理组件(MPM,连接处理组件(HTTP_CONNECTIONHTTP协议处理组件(HTTP_PROTOC)LHTTP请求处理组件(HTTP_REQUE$THTTP核心组件(HTTP_CORE核心模块组件(MOD_COREHTTP配置文件组件(HTTP_CONF)。
(1)HTTP_CONFI组件主要位于http_config.h和config.c中,对配置文件进行解析、处理和保存。
另外,HTTP_CONFI(组件还必须提供对配置数据访问的接口,其余组件在配置数据的任何时候都能够快地返回配置信息。
(2)进程并发处理组件(MPM,MPM!
件主要位于mpmi录下的各个文件中,比如PreforkMPM寸应的就是prefork.c。
MPM负责为Apache系统提供可靠、稳定、高效的进程和线程的并发处理。
任何时候,Apache中只能有一个MPM在运行,而且MPM、须在编译的时候指定,不允许动态加载。
(3)HTTP连接处理组件(HTTP_CONNECTIONHTTP_CONNECTIO组件主要位于http_connection.h和connection.c中。
该组件主要负责处理与HTTP连接相关的事情。
(4)HTTP协议处理组件(HTTP_PROTOC)L在Apache2.x系列中,HTTP_PROTOCOL
组件主要位于http_protocol.h和http_protocol.c中,主要负责处理HTTP/1.0及
HTTP/1.1协议的解析,比如解析http请求头、生成返回给客户端的响应包等。
所有与协议
相关的处理都由该组件完成。
(5)HTTP请求处理组件(HTTP_REQUE$THTTP_REQUES!
件主要位于http_request.h、
http_request.c及request.c三个文件中。
与Apache1.3相比,它增加了request.c文件。
与请求相关的函数全部定义在http_request.h中,函数实现则分散在两个.c中。
(6)HTTP核心组件(HTTP_CORE,在APACHE2.X系列中,还增加了一个HTTP_CORE
模块,它位于文件http_core.h和http_core.c中,该组件主要是将与HTTP协议相关的内
容从原来的核心模块中提取出来的。
最早的时候,一些与HTTP协议相关的指令(如
KeekpAliveTimeout、、MaxKeepAliveRequests及KeepAlive)都是直接有core.c核心模块完成的,这样导致核心模块与HTTP协议的耦合度过高,而APACHE勺设计者想要把APACHE
设计为一个通用的服务器,而不仅仅是一个Web服务器。
(7)核心模块组件(MOD_CORE核心模块(MOD_CORE由mod_core.h和core.c组
成,该模块的主要任务就是对核心需要的指令进行比较,比如
DocumentRoot等。
该模块在HTTP_CONFl(中被调用。
APACHE核心处理框架
最终,APACHE的核心功能层构造了HTTP服务器的基本功能的一个处理框架(流程),
如图3所示。
图3APACHE核心处理框架
这个框架包含了APAPCH对一个HTTP青求的不同的处理阶段。
模块扩展APACHE勺功能的实现是通过APACHES供的一种机制:
允许模块针对特定的HTTP请求,在这个框架里的已有的一些阶段中增加一些额外的处理;允许模块增加新的处理阶段。
APACH可选功能层(模块)
APACHES心层构造了一个基本的处理框架,并且为这个框架的各个分支(即HTTP请求
处理的各个阶段)提供了默认的实现,从而实现了APACHES为一个HTTP服务器应具有的最基本的功能。
也就是说,如果只有核心层的话,APACHE寸一次HTTP的请求只做默认的处理,例如:
在这个处理框架的内容生成阶段,APACHES是简单的将服务器上的文件(不管是html还是PHFP直接返回个客户端,不做额外处理。
这显然不是我们想要的,应该是根据文件类型的不同做不同的处理之后再返回给客户端。
APACHES心层通过一种机制(接口)让他构造的处理框架及其各个分支是可以扩展的:
可以增加额外的分支;可以在分支上增加额外的处理或者直接替代默认的处理行为。
APACHE
模块就是通过这个接口要么增加新的分支(如日志模块),要么为新的分支增加额外的处理
(如PHP模块为内容生成分支增加了对php文件进行处理的功能)。
挂钩(HOOK
之前,我们反复提到APACHES心层提供了一种机制,这种机制使得APACHES块能够扩
展核心层的功能。
那么,这种机制其实就是这里我们要讲的一挂钩。
核心层实现了一个处理HTTP请求的基本框架,那么一个挂钩就对对应了这个处理框架中的一个分支,即一次HTTP请求的一个处理阶段,核心层按照固定顺序运行每个挂钩具体实现中的挂钩调用函数,即,依次运行HTTP请求的一个处理阶段。
模块如何利用挂钩进行扩展的呢?
每一个挂钩都对应了多个挂钩处理函数,挂钩处理函
数具体处理HTTP请求,挂钩调用函数按照三种方式(后面详细介绍),调用挂钩处理函数,
模块通过增加新的挂钩(即增加新的处理阶段)或者为已有挂钩增加新的挂钩处理函数,来
实现对框架的扩展,从而实现了模块扩展核心层的功能。
预定义标准挂钩
在APACHE^,系统预定义了一些标准挂钩操作,分为两大类:
启动挂钩和请求挂钩。
启动挂钩是随着服务器启动进行调用的挂钩,包括:
pre_config,post_config,
open_logs,child_init。
请求挂钩则是服务器处理请求时进行调用的挂钩,连接阶段挂钩:
create_connection,
pre_connection,process_connection;Keep-alive循环中的挂钩:
create_request,post_read_request;请求处理挂钩:
translate_name,map_to_storage,header_parser,access_checker,check_user_id,auth_checker,type_checker,fixups,insert_filter,
handler;日志处理挂钩:
log_transaction。
挂钩使用
使用一个挂钩包括三个步骤:
挂钩声明,为处理框架增加一个新的分支(增加一个新的
处理阶段),只能声明一次;挂钩注册,对某个挂钩(处理阶段)感兴趣,定义一个该挂钩的挂钩处理函数,让APACH在这个阶段对特定的HTTP请求做更多的处理;挂钩调用,就是
调用挂钩的挂钩调用函数,挂钩调用函数中按一定方式调用已注册的挂钩处理函数。
挂钩声明
Apache中预定义了一些标准挂钩操作(见"预定义标准挂钩”节),也可以声明自己的
挂钩,如果一个模块要关心一个崭新的、其余任何模块都没有关心过的内容,那么它必须在
模块内部声明该挂钩。
挂钩只能被声明一次。
在Apache中声明一个挂钩,总是通过如下的宏来实现的。
#defineAP_DECLARE(type)type
#defineAPR_IMPLEMENT_HOOK_GET_PROTO(ns,link,name)\
link##_DECLARE(apr_array_header_t*)ns##_hook_get_##name(void)
#defineAPR_DECLARE_EXTERNAL_HOOK(ns,link,ret,name,args)\
/*挂钩函数类型*/
typedefretns##_HOOK_##name##_targs;\
/*挂钩注册函数原型*/
link##_DECLARE(void)ns##_hook_##name(ns##_HOOK_##name##_t*pf,\
constchar*const*aszPre,\
constchar*const*aszSucc,intnOrder);\
/*挂钩调用函数原型*/
link##_DECLARE(ret)ns##_run_##nameargs;\
APR_IMPLEMENT_HOOK_GET_PROTO(ns,link,name);\
/*结构类型,用来保存挂钩的相关定义信息(如,挂钩函数指针、挂钩名等),同一个挂钩
会有多个模块对其感兴趣并实现该挂钩,同一个挂钩所有的实现都保存在一个链表中,链表
中的每一个元素都是ns##_LINK_##name##_t结构。
*/
typedefstructns##_LINK_##name##_t\
{\
ns##_HOOK_##name##_t*pFunc;\
constchar*szName;\
constchar*const*aszPredecessors;\
constchar*const*aszSuccessors;\
intnOrder;\
}ns##_LINK_##name##_t;
#defineAP_DECLARE_HOOK(ret,name,args)\
APR_DECLARE_EXTERNAL_HOOK(ap,AP,ret,name,args)
ret是挂钩函数与挂钩调用函数的返回类型,name是挂钩名称,args是挂钩函数的参
数,通常以bracket形式出现。
如:
AP_DECLARE_HOOK(int,do_something,(request_rec*r,intn))。
挂钩数组声明
对于同一挂钩,不同模块对应于它的处理函数各不相同,为了能够保存各个模块对同一
挂钩的使用信息,APACHE核心使用apr_array_header_t数组保存对应于该挂钩的所有挂钩函数,该数组通过APR_HOOK_LIN声明:
#defineAPR_HOOK_LINK(name)\
apr_array_header_t*link_##name;
link_##name数组中每个元素的类型都是ap##_LINK_##name##_t结构,每个模块关于
该挂钩的实现在link_##name中占有一个位置。
挂钩结构
对于每一个挂钩,APACHE都会定义一个apr_array_header_t数组来保存它的相关信息,每一个实现了该挂钩的模块,会通过某种方式在apr_array_header_t数组中插入一个
ap##_LINK_##name##_t结构。
挂钩的apr_array_header_t数组定义是在声明该挂钩的C文件中,并且该挂钩数组将
在整个APACHE^保持唯一,当某个模块想要使用该挂钩的时候,只要访问模块内对应的挂钩数组即可。
为了便于各模块对数组的访问,原则上必须将数组声明为全局变量,这是最简单的方式。
但是,APACHE2.冲并不支持直接访问挂钩数组,弓I入了APR_HOOK_STRUCT所有对数组
的操作都只能通过该宏来实现。
#defineAPR_HOOK_STRUCT(members)\
staticstruct{members}_hooks;
该宏定义了一个限于模块内使用的结构_hooks,该模块内声明的所有挂钩对应的数组都
保存为_hooks的成员,如:
APR_HOOK_STRUCT(
APR_HOOK_LINK(header_parser)
APR_HOOK_LINK(pre_config)APR_HOOK_LINK(post_config)APR_HOOK_LINK(open」ogs)APR_HOOK_LINK(child」nit)APR_HOOK_LINK(handler)APR_HOOK_LINK(quick_handler)APR_HOOK_LINK(optional_fn_retrieve)
)
_hooks结构的定义为static,该结构是模块内的私有机构,外部模块无法直接访问
_hooks结构,并且只要声明了挂钩,就应该有一个对应的_hooks结构。
当某个模块想使用某个挂钩,它既不能直接访问该挂钩的挂钩数组,也不能访问被屏蔽的模
块内的_hooks结构,它只能使用该挂钩的注册函数ap_hook_name,ap_hook_name函数所做
的事情是访问_hooks结构中的某个数组,然后在数组中添加挂钩处理函数。
挂钩注册
如果模块对某个挂钩感兴趣,它就需要注册对应挂钩的处理函数。
模块对挂钩函数的注
册,通常是在模块结构中的register_hooks函数中调用对应挂钩的挂钩注册函数ap_hook_name来实现的。
查遍APACHE勺所有文件,也不能找到ap_hook_handler和ap_hook_post_config等函数声明和实现,因为挂钩注册函数是通过宏APR_IMPLEMENT_EXTERNAL_HOOK_BA实现的。
#defineAPR_IMPLEMENT_EXTERNAL_HOOK_BASE(ns,link,name)\
link##_DECLARE(void)ns##_hook_##name(ns##_HOOK_##name##_t*pf,constchar*const*aszPre,\
constchar*const*aszSucc,intnOrder)\
{\
ns##_LINK_##name##_t*pHook;\
if(!
_hooks.link_##iname)\
{\
_hooks.link_##name=apr_array_make(apr_hook_global_pool,1,sizeof(ns##_LINK_##name##_t));\
apr_hook_sort_register(#name,&_hooks.link_##name);\
}\
pHook=apr_array_push(_hooks.link_##name);\
pHook->pFunc=pf;\
pHook->aszPredecessors=aszPre;\pHook->aszSuccessors=aszSucc;\pHook->nOrder=nOrder;\pHook->szName=apr_hook_debug_current;\if(apr_hook_debug_enabled)\
apr_hook_debug_show(#name,aszPre,aszSucc);\
}\
挂钩使用
挂钩的使用实际上就是调用挂钩对应的挂钩函数。
所有的挂钩对外提供的调用形式都是
一样的ap_run_HOOKNAM,但是内部实现却不尽相同,差别分别体现于三个宏:
AP_IMPLEMENT_HOOK_VCAP_IMPLEMENT_HOOK_RUN_FI及SAP_IMPLEMENT_HOOK_RUN_ALL
AP_IMPLEMENT_HOOK_VQ调用函数将遍历挂钩数组,逐个执行针对该挂钩的所有注册过的挂钩函数,直到遍历调用结束,它没有任何返回值。
AP_IMPLEMENT_HOOK_RUN_Ai型与AP_IMPLEMENT_HOOK_VOID乎相同,唯一的不同就是ALL类型具有返回值。
只有调用请求发生错误时才会返回该错误值,同时退出遍历。
AP_IMPLEMENT_HOOK_RUN_FIRS!
,APACHES心从头逐一遍历挂钩数组中所注册的挂钩函数,直到遇到一个能够完成所提交任务的函数或发生错误为止。
挂钩函数允许返回四种值:
DONEOKDECLINED及错误码。
OK返回值意味着当前的挂钩处理函数已经正确处理完毕。
DECLINED返回值意味着当前的模块拒绝处理该结构,这实际上是通知apache核心应该
继续查找其余模块。
DONE返回值意味着当前模块已经完全完成了该挂钩对应阶段的任务,APACHES心将不
再继续调用其余挂钩,剩余的挂钩中只有log_transaction会被调用。
最后一种情况就是返回发生的错误码。
APACHE2.0系列的模块结构
APACHE2.0系列的模块结构,如图4所示。
\pHthc2.0Mwlulr
图4APACHE2.0系列的模块结构
描述模块本身的数据结构,即module」nfo。
挂钩注册函数,用于挂钩注册,对应
register_hooks方框。
模块配置数据结构,对应configuration方框。
指令表,command_rec
结构,描述了模块能处理的指令及相应的处理程序,对应handlers方框。
可选函数,对应
optionalfunctions方框。
过滤器相关处理,对应filters方框。
Apac
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- apache 模块化 体系结构