在ApacheHTTPD服务器中使用DSO完全分析
Apache HTTP 服務(wù)器是一個(gè)模塊化(或說積木式)的程序,管理員可以選擇一些模塊來增加服務(wù)器的某些功能。這些模塊,可以在創(chuàng)建服務(wù)器程序時(shí)靜態(tài)地編譯到httpd服務(wù)器的二進(jìn)制代碼中,也可以編譯成一些獨(dú)立于服務(wù)器程序的Dynamic Shared Objects (DSOs)文件。DSO 文件可以在編譯服務(wù)器程序時(shí)創(chuàng)建,也可以在以后利用Apache擴(kuò)展工具apxs來單獨(dú)創(chuàng)建。 這篇文檔,將描述如何使用DSO 模塊,以及其背后的原理。
實(shí)現(xiàn)
Apache HTTPD對DSO 的支持,即對單個(gè)模塊的動(dòng)態(tài)加載,是基于一個(gè)叫mod_so的模塊來實(shí)現(xiàn)的,此時(shí)mod_so必須被靜態(tài)地編譯到HTTP服務(wù)器內(nèi)核中。這是除了core以外唯一不能以dso方式編譯的模塊。實(shí)際操作時(shí),其它的Apache模塊可以在編譯服務(wù)器程序時(shí)通過單獨(dú)指定來將其編譯為DSO文件,正如安裝文檔中講述的,此時(shí)configure的設(shè)置參數(shù)應(yīng)為--enable-xxxx=shared(xxxx為模塊的名字,如rewrite等)。 當(dāng)一個(gè)模塊被編譯為一個(gè)名為mod_foo.so的DSO文件后,就可以在httpd.conf文件中用mod_so的LoadModule命令,告訴服務(wù)器在啟動(dòng)或重新啟動(dòng)時(shí)將此模塊加載。
為了簡化創(chuàng)建Apache模塊(尤其是第三方模塊)的DSO文件的過程,apache提供了一個(gè)新工具名叫apxs(APache eXtenSion)。它可以脫離apache的源碼將模塊編譯成DSO文件。它的實(shí)現(xiàn)思路非常簡單: 在安裝Apache時(shí),configure腳本的 make install 過程會(huì)安裝Apache的C頭文件,并在apxs程序(apxs是一個(gè)perl腳本)中對依賴于具體平臺(tái)的編譯器和連接器設(shè)置一些標(biāo)志(Flag),以供創(chuàng)建DSO文件。通過這種方式,用戶就可以利用apxs在沒有Apache源碼樹且無需針對當(dāng)前平臺(tái)的編譯器和連接器進(jìn)行配置(以生成DSO格式目標(biāo)文件)的情況下編譯Apache模塊了。
使用概要說明
創(chuàng)建和安裝一個(gè) Apache發(fā)布的(distributed) 模塊,比方說將mod_foo.c編譯成mod_foo.so:
$ ./configure --prefix=/path/to/install --enable-foo=shared
$ make install
創(chuàng)建和安裝一個(gè)第三方的Apache模塊,比方說將mod_foo.c編譯成mod_foo.so:
$ ./configure --add-module=module_type:/path/to/3rdparty/mod_foo.c --enable-foo=shared
$ make install
為以后安裝(非HTTPD編譯時(shí)安裝)模塊配置Apache:
$ ./configure --enable-so
$ make install
(要編譯全部Aapache模塊,用./configure --enable-mods-shared=all --with-egd --with-devrandom --enable-so,但對experimental一類的模塊,需要特別指定,如./configure --enable-mods-shared=all --with-egd --with-devrandom --enable-so --enable-cache=shared --enable-disk_cache=shared --enable-mem_cache=shared --enable-proxy=shared --enable-proxy_connect=shared --enable-proxy_ftp=shared --enable-proxy_http=shared --enable-file_cache=shared --enable-charset_lite=shared --enable-case_filter=shared --enable-case_filter_in=shared --enable-ssl=shared 。具體有哪些模塊可以編譯而沒有打開編譯開關(guān),可在前面的那個(gè)configure運(yùn)行的最后看看哪一個(gè)是no.)
利用apxs在沒有Apache源碼樹的情況下,創(chuàng)建和安裝第三方的Apache模塊:
$ cd /path/to/3rdparty
$ apxs -c mod_foo.c
$ apxs -i -a -n foo mod_foo.la
在所有的情況下,當(dāng)一個(gè)模塊編譯完成后,必須在httpd.conf使用LoadModule命令在告訴 Apache激活這個(gè)模塊.
背景知識(shí)
在現(xiàn)代的Unix的派生版本中,有一種非常好的機(jī)制,叫做Dynamic Shared Objects (DSO) 的動(dòng)態(tài)連接/和加載,它提供了一種方法,將一段代碼編譯成一種特殊格式后可在一個(gè)可執(zhí)行程序運(yùn)行時(shí)將這段程序加載到它的地址空間中。
這種加載通過可以通過兩種方式做到: 在一個(gè)可執(zhí)行程序開始運(yùn)行后通過一個(gè)叫l(wèi)d.so的系統(tǒng)程序自動(dòng)加載,或在可執(zhí)行程序內(nèi)部通過Unix加載器(loader)的系統(tǒng)編程接口的系統(tǒng)調(diào)用dlopen()/dlsym()來手工加載。
在第一種方式中,DSO通常被叫作共享庫或DSO庫,以libfoo.so或libfoo.so.1.2的形式命名。它們被存放在系統(tǒng)目錄中(通常是/usr/lib),它們與可執(zhí)行程序的聯(lián)系是在編譯這個(gè)可執(zhí)行程序時(shí),通過傳遞給連接器一個(gè)-lfoo參數(shù)來建立的。這里對庫的引用直接編碼在可執(zhí)行程序中,因而在程序運(yùn)行時(shí),Unix加載器會(huì)通過以下途徑尋找libfoo.so:在系統(tǒng)目錄/usr/lib下,在通過-R連接參數(shù)傳遞給連接器后被編碼在可執(zhí)行程序中的路徑中,在通過環(huán)境變量LD_LIBRARY_PATH指定的目錄中。加載器會(huì)解析出來那些在可執(zhí)行程序中使用但是在DSO定義的標(biāo)志(symbol)。
可執(zhí)行程序中的標(biāo)志,通常不會(huì)被DSO引用(因?yàn)樗且粋€(gè)可重用的基本代碼庫),因而就不再進(jìn)行進(jìn)一步的解析??蓤?zhí)行程序自己不需要做任何事情就可以使用來自DSO的標(biāo)志,因?yàn)閁nix加載器已經(jīng)做了相關(guān)的解析工作。(實(shí)際上,加載ld.so的代碼是使用動(dòng)態(tài)庫的可執(zhí)行程序啟動(dòng)代碼的一部分). 動(dòng)態(tài)加載基本代碼庫的優(yōu)點(diǎn)是很明顯的:庫的代碼只需在一個(gè)系統(tǒng)庫(如libc.so)中保存一次,這樣可以節(jié)省每個(gè)程序的磁盤空間。
在第二種方式中,DSO通常被叫作共享對象或DSO文件,命名它們時(shí)可以使用任意的擴(kuò)展名,雖然規(guī)范的命名是foo.so的樣子。這些文件通常存放在程序所在的目錄(或子目錄)中,它們與執(zhí)行它們的程序沒有自動(dòng)建立的聯(lián)系。相反,可執(zhí)行程序在運(yùn)行時(shí)通過dlopen手工將DSO加載。此時(shí),來自DSO供執(zhí)行程序用的標(biāo)志沒有被解析。相反,Unix加載器自動(dòng)解析所有DSO中使用的來自可執(zhí)行程序和它已經(jīng)加載的DSO 庫的標(biāo)志(尤其是來自無處不在的libc.so的所有標(biāo)志)。在這種方式中,DSO取得可執(zhí)行程序的標(biāo)志集合的信息,就象是被靜態(tài)地連接到可執(zhí)行程序中一樣。
最后,為利用DSO's API,可執(zhí)行程序須通過dlsym()來解析來自DSO的特定標(biāo)志,供在以后的分派表等處使用。也就是說:可執(zhí)行程序要想使用來自DSO的標(biāo)志,須手工解析它。這樣一種機(jī)制的優(yōu)點(diǎn),不需要的程序段不必加載(因而可以節(jié)省內(nèi)存的使用) ,直到我們討論的程序需要它時(shí)。當(dāng)需要時(shí),這些程序段可以被動(dòng)態(tài)的加載,來擴(kuò)展基本程序的功能。
雖然DSO機(jī)制聽起來簡單,用起來只少有一個(gè)比較困難的步驟,就是當(dāng)用DSO來擴(kuò)展程序的功能時(shí)(第二種方式)時(shí),對來自可執(zhí)行程序、供DSO使用的標(biāo)志的解析。為什么呢? 因?yàn)?#34;反向解析" DSO 使用的來自可執(zhí)行程序標(biāo)志集合的標(biāo)志是與函數(shù)庫的設(shè)計(jì)相逆的 (函數(shù)庫沒有任何關(guān)于那些使用它的程序的信息),而且沒有平臺(tái)提供這種功能,這也不是一個(gè)標(biāo)準(zhǔn)化的功能。實(shí)際上,可執(zhí)行程序的全局標(biāo)志常常不能再次輸出,因而也無法供DSO使用。要利用DSO來動(dòng)態(tài)擴(kuò)展一個(gè)程序的功能,找到一種方法來強(qiáng)制連接器輸出所有全局標(biāo)志是必須解決的主要問題。
共享庫的方法就是一個(gè)典型,因?yàn)樗荄SO機(jī)制最初設(shè)計(jì)的目標(biāo),因而它被用于操作系統(tǒng)提供的幾乎所有類型的函數(shù)庫中。從另一方面來說,利用共享對象來擴(kuò)展功能的程序并不是很多。
到1998年,只有很少的軟件包在程序運(yùn)行時(shí)利用DSO機(jī)制來擴(kuò)展它們的功能:Perl 5(通過它的XS機(jī)制和DynaLoader模塊), Netscape Server,等。從版本1.3開始, Apache 也加入了這個(gè)群體,因?yàn)锳pache早就用模塊的概念來擴(kuò)展它的功能,且在內(nèi)容利用基于分派鏈(dispatch-list-based )的方法來將外部的模塊連接到Apache的核心功能中。因此,Apache實(shí)際上注定要用DSO來在運(yùn)行時(shí)加載模塊的。
長處和不足
上述的基于DSO的功能有以下優(yōu)點(diǎn):
服務(wù)器在運(yùn)行時(shí)更加靈活,因?yàn)閷?shí)際的服務(wù)器進(jìn)程可以通過配置文件的LoadModule命令動(dòng)態(tài)的組配,而不必在編譯時(shí)通過配置參數(shù)指定。例如,通過這種方式,雖然只安裝了一次,但服務(wù)器可以以多種形態(tài)運(yùn)行(如標(biāo)準(zhǔn)版本或SSL版本,簡化版本或增強(qiáng)版本[含mod_perl,php3等])
即使在安裝完成后,服務(wù)器仍可以很方便地用第三方的模塊進(jìn)行功能擴(kuò)展。這至少對銷售商的軟件支持有幫助,他們可以創(chuàng)建一個(gè)apache的核心程序包,和一個(gè)包含PHP3, mod_perl, mod_fastcgi等擴(kuò)展功能的擴(kuò)展包。
更容易地開發(fā) Apache模塊原型,因?yàn)榻栌肈SO和apxs,你可以脫離Apache的源碼而只需apxs -i命令就可以開發(fā)和編譯模塊,利用apachectl restart 命令,就可以讓新開發(fā)的模塊在在apache服務(wù)器中運(yùn)行。
DSO 也有下列不足
DSO并不是在任何平臺(tái)都可以使用,因?yàn)橛幸恍┢脚_(tái)不支持動(dòng)態(tài)將一段代碼加載到另一個(gè)程序的地址空間中
服務(wù)器在啟動(dòng)時(shí)慢大約20%,因?yàn)榧虞d器要作標(biāo)志解析。
在運(yùn)行時(shí),在有些平臺(tái)上服務(wù)器大約慢5%,因?yàn)镻IC( position independent code )代碼需要更復(fù)雜的組配技巧來解決相對地址的問題,而對絕對地址的情況沒有這種開銷所以會(huì)快一些。
因?yàn)椴⒉皇撬械钠脚_(tái)都支持DSO模塊連接(ld -lfoo)其它基于DSO的庫(如基于out的平臺(tái)通常不提供這個(gè)功能而基于ELF的平臺(tái)則可以),所以不能將DSO機(jī)制用于所有類型的模塊。換句話說,可以編譯為DSO文件的模塊限制為那些:引用的標(biāo)志只來自apache內(nèi)核、來自C函數(shù)庫(libc)、來自其它的Aapche內(nèi)核使用的動(dòng)態(tài)或靜態(tài)庫、或含有PIC代碼的靜態(tài)庫文件(libfoo.a)。使用其它代碼的唯一機(jī)會(huì),要么確定apache內(nèi)核已經(jīng)對此引用,要能自己通過dlopen()加載代碼。
總結(jié)
以上是生活随笔為你收集整理的在ApacheHTTPD服务器中使用DSO完全分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 谁能帮看看这张邮票上说的啥 啥意思?
- 下一篇: 黄山风景区山上住宿攻略