Apache源代码分析——关于模块结构的几个重要概念
Apache源代码分析——关于模块结构的几个重要概念 转载请注明来源:http://blog.csdn.net/tingya
本文分析了Apache中关于模块的几个重要的概念
///////////////////////////////////////////////////////////////////////////////////////
关于模块的几个重要的全局变量
理解Apache模块的概念之前我们首先必须弄清楚apache中关于模块的几个重要概念和数据结构。
1. DSO(Dynamic Shared Object,动态共享对象)
Apache 服务器的体系结构的最大的特点就是高度模块化,这一点到2.0版本的时候几乎发挥到了极致。除了少数的几个核心文件外,Apache中大部分功能都被模块化。模块化的最大的优势就是用户可以根据自己的实际需要进行裁减和增加。模块的存在有两种方式,一种就是在编译Apache的时候跟核心文件一起编译,这时候的模块我们称之为静态链接编译模块;另一种存在方式就是独立于Apache的核心文件,这种文件何时编译与Apache的核心文件无关,核心文件也不关心其存在。核心文件只有在需要的时候才去找它并将它装入自己的执行空间。这种方式称之为动态状态模块。
DSO的产生当然离不开操作系统的支持。目前的不管UNIX还是Linux大多提供了对动态共享对象或者动态链接库进行加载何卸载的机制。加载的方法通常有两种:其一是在可执行文件启动时候由系统程序ld.so自动加载;其二是在执行程序中手工地通过Unix提供的动态链接库加载接口进行加载。
按照第一种方法,动态链接库比如libfoo.so或者libfoo.so.1.2通常被存储在目录/usr/lib中。使用libfoo.so库的程序只需要在编译程序的时候加上编译选项-lfoo就可以建立到动态链接库的链接。通常
而在第二种方法种,动态链接库可以使用任何的文件名(规范的文件名称为foo.so),而且也不一定要存储在/usr/lib目录中,其可以存储于任何目录中,也不会自动建立指向其所用的可执行程序的链接,而是由可执行文件在运行的时候自己调用类似dlopen之类的接口将动态链接库加载到自己的地址空间,同时也不会为可执行程序解析动态链接库中的符号,包括函数名称、变量名称等等,这些工作必须由可执行程序自行调用dlsym之类的函数进行解析。
。。。。。
Apache 2.0提供了下面的几个命令用于生成DSO共享链接库,简要说明如下:
1. 编译并安装已发布的Apache模块,比如编译mod_foo.c为mod_foo.so的DSO模块:
$ ./configure --prefix=/path/to/install --enable-foo=shared
$ make install
2. 编译并安装第三方Apache模块, 比如编译mod_foo.c为mod_foo.so的DSO模块:
$ ./configure --add-module=module_type:/path/to/3rdparty/mod_foo.c --enable-foo=shared
$ make install
3. 配置Apache以共享后安装的模块:
$ ./configure --enable-so
$ make install
4. 用apxs在Apache源代码树以外编译并安装第三方Apache模块,比如编译mod_foo.c为mod_foo.so的DSO模块:
$ cd /path/to/3rdparty
$ apxs -c mod_foo.c
$ apxs -i -a -n foo mod_foo.la
共享模块编译完毕以后,都必须在httpd.conf中用LoadModule指令使Apache激活该模块。
2. Linux中DSO函数操作
void* dlopen(const char *pathname, int mode);
该函数函数来加载动态库,其中pathname是需要加载的库的路径名称,mode则是加载的方式,可以是三个值:RTLD_LAZY用来表示认为未定义的符号是来自动态链接库的代码;RTLD_NOW则表示要在dlopen返回前确定所有未定义的符号,如果不能完成则失败;而RTLD_GLOBAL则意味着动态链接库中定义的外部符号将可以由随后加载的库所使用。如果函数执行成功,其将返回动态链接库的一个句柄。
一旦对动态库进行了加载,我们则可以通过dlsym函数获取库中的函数调用以及各种定义的符号等等。其函数原型如下:
void* dlsym(void* handle, char* symbol);
其中,handle是加载的动态链接库的句柄,其通常是dlopen函数的操作结果;symbol则是需要得到的动态链接库中的符号名称。如果找不到symbol,函数将返回NULL。
在所有的操作结束后,Linux可以通过dlclose将dlopen先前打开的共享对象从当前进程断开,不过只有动态链接库的使用记数为0的时候该共享对象才会真真被卸载。dlclose的函数原型如下:
int dlclose(void* handle);
一旦使用dlclose关闭了对象,dlsym就再也不能使用它的符号了。
下面的代码简单的演示了dlopen、dlsym、dlclose的三步曲的使用。
void* handle, *handle2;
handle = dlopen('libdisplay.so', RTLD_LAZY);
if (handle != NULL)
{
handle2 = dlsym(handle, 'draw');
if (handle2 != NULL){
…… /* use the function */
}
/* When finished, unload the shared library */
dlclose(handle);
}
3. Apache中DSO处理模块
Apache中对动态链接库的处理是通过模块mod_so来完成的,该模块与其余的所有模块相比,没有什么特殊之处,因此从某种角度而言,其就是一个普通的模块。不过由于其作用是用来装载其余的模块,因此该模块不能被动态加载,它只能被静态编译进Apache的核心。这意味着Apache一启动,该模块就必须立即起作用。mod_so模块是Apache中除了core模块之外唯一不能作为DSO模块而存在的模块。想想,如果mod_so模块也要被动态加载,那么谁来加载它呢?
4. Apache中关于模块的几个全局变量
Apache中定义了一些与模块相关的全局变量,它们的作用相似,但存在差异。
■ap_preloaded_modules[]
该数组称之为预装载模块数组,其中定义了所有的Apache中默认的静态编译的模块。尽管这些模块已经被编译进Apache中,但是其不一定能够发挥作用,模块能否发挥作用,取决于该模块是否被“激活”。只有激活的模块才能起作用。在Apache1.3中,可以通过指令AddModule来激活某个模块。
module *ap_preloaded_modules[] = {
&core_module,
&mpm_netware_module,
&http_module,
&so_module,
&mime_module,
……
NULL
};
■ap_prelinked_modules[]
该数组称之为预链接模块数组,该数组定义了所有的Apache中默认的在Apache启动后就处于“激活”状态的模块,其定义简化如下:
module *ap_prelinked_modules[] = {
&core_module,
&mpm_netware_module,
&http_module,
&so_module,
&mime_module,
……
NULL
};
该数组中定义的所有的模块在Apache启动后由于处于“激活”状态,因此可以立即相应核心的请求
这两个全局数组是从以前的Apache版本延续而来的。正如前面所说,在Apache1.3版本中,这两个数组未必完全相同。不过在Apache2.0中,两个数组已经没有差异了,这意味着一个模块一旦被静态编译,其就立即处于激活状态,这也是Apache2.0中删除了AddModule指令的原因。
■ap_loaded_modules数组
尽管Apache对于所有的静态编译的模块都是立即激活它,这并意味着Apache对所有的模块都是这样。如果你某个模块不是默认的,而是第三方模块的话,那么Apache即使将其装入也不一定就立即激活它。ap_loaded_modules数组用来保存所有的已经被装入的模块,包括默认的和第三方的;包括激活的和非激活的。
■ap_top_modules链表
与ap_loaded_modules数组对应,ap_top_modules链表用来保存Apache中所有的被激活的模块,包括默认的激活模块和激活的第三方模块。
关于作者
张中庆,目前主要的研究方向是嵌入式浏览器,移动中间件以及大规模服务器设计。目前正在进行Apache的源代码分析,计划出版《Apache源代码全景分析》上下册。Apache系列文章为本书的草案部分,对Apache感兴趣的朋友可以通过flydish1234 at sina.com.cn与之联系!
如果你觉得本文不错,请点击文后的“推荐本文”链接!!