歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux綜合 >> Linux資訊 >> 更多Linux >> Apache源代碼分析——關於模塊結構的幾個重要概念

Apache源代碼分析——關於模塊結構的幾個重要概念

日期:2017/2/27 9:40:41   编辑:更多Linux

轉載請注明來源: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與之聯系! 如果你覺得本文不錯,請點擊文後的“推薦本文”鏈接!!



Copyright © Linux教程網 All Rights Reserved