apache模块化体系结构简析.doc_第1页
apache模块化体系结构简析.doc_第2页
apache模块化体系结构简析.doc_第3页
apache模块化体系结构简析.doc_第4页
apache模块化体系结构简析.doc_第5页
已阅读5页,还剩7页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

apache模块化体系结构简析目录APACHE的体系结构概述1APACHE核心功能层3APACHE核心组件3APACHE核心处理框架4APACHE可选功能层(模块)4挂钩(HOOK)5预定义标准挂钩5挂钩使用5挂钩声明5挂钩数组声明6挂钩结构6挂钩注册7挂钩使用8APACHE 2.0系列的模块结构8模块与核心的交互10APACHE的体系结构概述APACHE采用了分层与模块化的体系结构,如图1所示。图1 Apache分层与模块化体系结构加上操作系统层,整个Apache可以被分隔为五层,各层次的功能如下:(1)操作系统支持层,操作系统本身提供的底层功能,比如进程和线程、进程和线程间的通信、网络套接字通信、文件操作等。(2)可移植运行库层,不同的操作系统提供的底层API存在着很大的差异。对于Apache设计者而言,除了考虑WWW和服务器功能的实现之外,还必须考虑不同操作系统的API细节问题。显然,合理的做法就是将不同操作系统的底层细节封装起来形成操作系统API的适配并将其隐藏起来。从Apache 2.0开始,Apache就将专门封装不同操作系统API的任务独立出来形成一个新的项目APR,全称为Apache可移植运行库(Apache Portable Runtime,APR)。APR的任务就是屏蔽底层的操作系统API细节,对于所有的操作系统,提供一个完全相同的函数接口。这样,Apache开发者 就不必顾虑操作系统细节,而只要开发上层功能即可。比如对于进程创建,如图2所示。图2 进程创建不同的操作系统提供的创建进程的API是不同的,Unix下通用的是fork(),Windows下则是 CreateProcess(),OS/2、Netware及BeOS中的API也迥然不同。APR将所有的创建细节封装起来,提供了统一的对外接口 apr_proc_create()。这样,APR的使用者如果要创建进程,则只须调用apr_proc_create(),不管它将要运行于哪个操作系统平台。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模块加载等。Apache Module API,Apache最基本的核心功能由Apache核心完成,除此之外,核心无法提供的功能则全部由模块提供。为了允许这些模块能够完全控制Apache 的处理,Apache核心必须提供对应的API。在Apache中,这些API是指每个模块中包含一系列的函数(核心在处理HTTP请求的时候用来将消息传递给模块),以及一系列的以apr开始的函数。(4)可选功能层,可选功能层通常指Apache模块。按需载入,比如,如果需要Apache服务器支持安全套接字层(Secure Socket Layer,SSL),那么毫无疑问,我们必须将mod_ssl模块加载到核心中。目前,Apache中的模块很多,Apache能够支持的完整的注册过的模块信息可以在上 查看。(5)第三方支持库,在Apache的一些模块中会使用到第三方的开发库,比如mod_ssl就使用了OpenSSL,mod_perl则使用了Perl开发库。这些第三方支持库虽然被Apache使用,但严格来说它们并不属于Apache的一部分。APACHE体系结构的模块化特点主要体现在第三层(核心功能层)与第四层(可选功能层),Apache采用的模块化的体系结构,使它作为一个HTTP服务器的大部分功能都被分割为相互独立的模块,这样,通过增加或删除模块就可以扩展和修改Apache提供的功能。APACHE核心功能层APACHE核心功能层实现了APAPCHE作为一个HTTP服务器应具备的基本功能,包括:启动和停止Apache,处理配置文件,接受和处理HTTP连接,读取HTTP请求并对该请求进行处理,处理HTTP协议等。APACHE核心组件从实现这些基本功能的源代码来看,Apache的核心功能层可以有以下的几个组件组成:配置文件组件(HTTP_CONFIG),进程并发处理组件(MPM),连接处理组件(HTTP_CONNECTION),HTTP协议处理组件(HTTP_PROTOCOL),HTTP请求处理组件(HTTP_REQUEST),HTTP核心组件(HTTP_CORE),核心模块组件(MOD_CORE),HTTP配置文件组件(HTTP_CONFIG)。(1)HTTP_CONFIG组件主要位于http_config.h和config.c中,对配置文件进行解析、处理和保存。另外,HTTP_CONFIG组件还必须提供对配置数据访问的接口,其余组件在配置数据的任何时候都能够快地返回配置信息。(2)进程并发处理组件(MPM),MPM组件主要位于mpm目录下的各个文件中,比如Prefork MPM对应的就是prefork.c。MPM负责为Apache系统提供可靠、稳定、高效的进程和线程的并发处理。任何时候,Apache中只能有一个 MPM在运行,而且MPM必须在编译的时候指定,不允许动态加载。(3)HTTP连接处理组件(HTTP_CONNECTION),HTTP_CONNECTION组件主要位于http_connection.h和connection.c中。该组件主要负责处理与HTTP连接相关的事情。(4)HTTP协议处理组件(HTTP_PROTOCOL),在Apache 2.x系列中,HTTP_PROTOCOL组件主要位于http_protocol.h和http_protocol.c中,主要负责处理 HTTP/1.0及HTTP/1.1协议的解析,比如解析http请求头、生成返回给客户端的响应包等。所有与协议相关的处理都由该组件完成。(5)HTTP请求处理组件(HTTP_REQUEST),HTTP_REQUEST组件主要位于http_request.h、http_request.c及request.c三个文件中。与 Apache 1.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_CONFIG中被调用。APACHE核心处理框架最终,APACHE的核心功能层构造了HTTP服务器的基本功能的一个处理框架(流程),如图3所示。图3 APACHE核心处理框架这个框架包含了APAPCHE对一个HTTP请求的不同的处理阶段。模块扩展APACHE的功能的实现是通过APACHE提供的一种机制:允许模块针对特定的HTTP请求,在这个框架里的已有的一些阶段中增加一些额外的处理;允许模块增加新的处理阶段。APACHE可选功能层(模块)APACHE核心层构造了一个基本的处理框架,并且为这个框架的各个分支(即HTTP请求处理的各个阶段)提供了默认的实现,从而实现了APACHE作为一个HTTP服务器应具有的最基本的功能。也就是说,如果只有核心层的话,APACHE对一次HTTP的请求只做默认的处理,例如:在这个处理框架的内容生成阶段,APACHE就是简单的将服务器上的文件(不管是html还是PHP)直接返回个客户端,不做额外处理。这显然不是我们想要的,应该是根据文件类型的不同做不同的处理之后再返回给客户端。 APACHE核心层通过一种机制(接口)让他构造的处理框架及其各个分支是可以扩展的:可以增加额外的分支;可以在分支上增加额外的处理或者直接替代默认的处理行为。APACHE模块就是通过这个接口要么增加新的分支(如日志模块),要么为新的分支增加额外的处理(如PHP模块为内容生成分支增加了对php文件进行处理的功能)。 挂钩(HOOK)之前,我们反复提到APACHE核心层提供了一种机制,这种机制使得APACHE模块能够扩展核心层的功能。那么,这种机制其实就是这里我们要讲的挂钩。核心层实现了一个处理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。挂钩使用使用一个挂钩包括三个步骤:挂钩声明,为处理框架增加一个新的分支(增加一个新的处理阶段),只能声明一次;挂钩注册,对某个挂钩(处理阶段)感兴趣,定义一个该挂钩的挂钩处理函数,让APACHE在这个阶段对特定的HTTP请求做更多的处理;挂钩调用,就是调用挂钩的挂钩调用函数,挂钩调用函数中按一定方式调用已注册的挂钩处理函数。挂钩声明Apache中预定义了一些标准挂钩操作(见“预定义标准挂钩”节),也可以声明自己的挂钩,如果一个模块要关心一个崭新的、其余任何模块都没有关心过的内容,那么它必须在模块内部声明该挂钩。挂钩只能被声明一次。在Apache中声明一个挂钩,总是通过如下的宏来实现的。#define AP_DECLARE(type) type#define APR_IMPLEMENT_HOOK_GET_PROTO(ns,link,name) link#_DECLARE(apr_array_header_t *) ns#_hook_get_#name(void)#define APR_DECLARE_EXTERNAL_HOOK(ns,link,ret,name,args) /*挂钩函数类型*/typedef ret ns#_HOOK_#name#_t args; /*挂钩注册函数原型*/link#_DECLARE(void) ns#_hook_#name(ns#_HOOK_#name#_t *pf, const char * const *aszPre, const char * const *aszSucc, int nOrder); /*挂钩调用函数原型*/link#_DECLARE(ret) ns#_run_#name args; APR_IMPLEMENT_HOOK_GET_PROTO(ns,link,name); /*结构类型,用来保存挂钩的相关定义信息(如,挂钩函数指针、挂钩名等),同一个挂钩会有多个模块对其感兴趣并实现该挂钩,同一个挂钩所有的实现都保存在一个链表中,链表中的每一个元素都是ns#_LINK_#name#_t 结构。*/typedef struct ns#_LINK_#name#_t ns#_HOOK_#name#_t *pFunc; const char *szName; const char * const *aszPredecessors; const char * const *aszSuccessors; int nOrder; ns#_LINK_#name#_t;#define AP_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,int n)。挂钩数组声明对于同一挂钩,不同模块对应于它的处理函数各不相同,为了能够保存各个模块对同一挂钩的使用信息,APACHE核心使用apr_array_header_t数组保存对应于该挂钩的所有挂钩函数,该数组通过APR_HOOK_LINK声明:#define APR_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.0中并不支持直接访问挂钩数组,引入了APR_HOOK_STRUCT宏,所有对数组的操作都只能通过该宏来实现。#define APR_HOOK_STRUCT(members) static struct 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_logs)APR_HOOK_LINK(child_init)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_BASE来实现的。#define APR_IMPLEMENT_EXTERNAL_HOOK_BASE(ns,link,name) link#_DECLARE(void) ns#_hook_#name(ns#_HOOK_#name#_t *pf,const char * const *aszPre, const char * const *aszSucc,int nOrder) ns#_LINK_#name#_t *pHook; if(!_hooks.link_#name) _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_HOOKNAME,但是内部实现却不尽相同,差别分别体现于三个宏:AP_IMPLEMENT_HOOK_VOID、AP_IMPLEMENT_HOOK_RUN_FIRST及AP_IMPLEMENT_HOOK_RUN_ALL。AP_IMPLEMENT_HOOK_VOID,调用函数将遍历挂钩数组,逐个执行针对该挂钩的所有注册过的挂钩函数,直到遍历调用结束,它没有任何返回值。AP_IMPLEMENT_HOOK_RUN_ALL类型与AP_IMPLEMENT_HOOK_VOID几乎相同,唯一的不同就是ALL类型具有返回值。只有调用请求发生错误时才会返回该错误值,同时退出遍历。AP_IMPLEMENT_HOOK_RUN_FIRST类型,APACHE核心从头逐一遍历挂钩数组中所注册的挂钩函数,直到遇到一个能够完成所提交任务的函数或发生错误为止。挂钩函数允许返回四种值:DONE、OK、DECLINED及错误码。OK返回值意味着当前的挂钩处理函数已经正确处理完毕。DECLINED返回值意味着当前的模块拒绝处理该结构,这实际上是通知apache核心应该继续查找其余模块。DONE返回值意味着当前模块已经完全完成了该挂钩对应阶段的任务,APACHE核心将不再继续调用其余挂钩,剩余的挂钩中只有log_transaction会被调用。最后一种情况就是返回发生的错误码。APACHE 2.0系列的模块结构APACHE 2.0系列的模块结构,如图4所示。图4 APACHE 2.0系列的模块结构描述模块本身的数据结构,即module_info。挂钩注册函数,用于挂钩注册,对应register_hooks方框。模块配置数据结构,对应configuration方框。指令表,command_rec结构,描述了模块能处理的指令及相应的处理程序,对应handlers方框。可选函数,对应optional functions方框。过滤器相关处理,对应filters方框。Apache模块以_module结尾,如alias_module、access_module等,对应的文件名以mod_开始,如mod_alias.c、mod_access.c等,在每一个模块文件的末尾,都会存在一个模块结构。struct module_struct int version; int minor_version; int module_index; const char *name; void *dynamic_load_handle; struct module_struct *next; unsigned long magic;void (*rewrite_args) (process_rec *process); void *(*create_dir_config) (apr_pool_t *p, char *dir); void *(*merge_dir_config) (apr_pool_t *p, void *base_conf, void *new_conf); void *(*create_server_config) (apr_pool_t *p, server_rec *s); void *(*merge_server_config) (apr_pool_t *p, void *base_conf, void *new_conf); const command_rec *cmds; void (*register_hooks) (apr_pool_t *p);module结构是整个模块化体系结构的核心部分,Apache核心服务总是通过module结构与具体的模块打交道,而该结构通常位于每个模块文件的最末尾。version和minor_version是当前Apache API版本号,不是模块的版本号,通过这两个字段,可检测模块是否与当前的服务器兼容。APACHE核心通过模块数组进行模块保存,每个模块将当前模块在数组中的索引保存在模块内部,即module_index,要使用的时候,取出模块的module_index,获取数据中module_index索引出的数据。name用来记录当前模块的名称。dynamic_load_module是内部的DSO处理句柄,通过该句柄可以动态加载指定模块。Apache的模块之间通过next指针组成模块链表。上述几个字段不允许由模块编写者自行赋值,因为任何字段出现错误都会使服务器变得不稳定。APACHE开发者提供了两个宏填充初始的模块结构,分别为STANDARD20_MODULE_STUFF(用于普通的APAHCE模块)和MPM20_MODULE_STUFF(用于M

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论