Apache模塊開發(fā)指南_第1頁
Apache模塊開發(fā)指南_第2頁
Apache模塊開發(fā)指南_第3頁
Apache模塊開發(fā)指南_第4頁
Apache模塊開發(fā)指南_第5頁
已閱讀5頁,還剩72頁未讀 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

ApacheWeb服務器簡史Apache1ApacheWeb服務器誕生于1995年。它起源于早期的由NCSA編寫的NCSA服務器,并在其基礎上進行構建。第一個以Apache命名的服務器產(chǎn)品發(fā)布于1999年12月,版本為1.0.0。作為Web服務器,Apache隨即取得成功。到1996年4月,Apache已經(jīng)取代NCSA服務器,成為Internet上使用最廣泛的Web服務器,至今依然如此。Apache并不是通常意義上的應用平臺:原生API非常有限,同其他產(chǎn)品具有的高級別編程層次相比,Apache需要開發(fā)人員付出更多的努力來達到同樣的效果。然而,在一些非常有用的功能模塊中最值得一提的是已經(jīng)開發(fā)出來的十分優(yōu)秀的mod_rewrite模塊。Apache引起第一次比較大的反響的應用開發(fā)框架是Perl語言,由CGI和mod_perl支持。由于mod_perl第一次采用了真正有用而且容易使用的API,大量的編程書籍和開發(fā)人員都集中在Perl上。很快,JavaServlet及大量的腳本語言,包括如今的市場領頭羊PHP等,都發(fā)布了各自的API。Apache1服務器的最后一個主要版本為1.3,發(fā)布于1998年6月。盡管新的開發(fā)工作移植到Apache2已經(jīng)很長時間,但Apache1.3仍然處于維護模式,至今依然流行。Apache2Apache的開發(fā)人員認識到Apache最初的架構具有局限性,比較粗糙,于是在2000年開始建立新的代碼倉庫(codebase)主分支,并在此代碼倉庫的基礎上于2002年4月創(chuàng)建了Apache2.0的第一個發(fā)布版本。Apache2包括以下優(yōu)良特性:原生API得到很大幅度改進,使APR庫成為單獨的實體。這在很大程度上幫助開發(fā)人員克服了C語言編程的缺陷,特別是交叉編譯平臺和資源管理方面的缺陷。通過使用Apache2,C程序員可以達到通常被認為是高層次語言和腳本語言才能達到的高效率。新的拓展架構帶來了全新層次的應用程序開發(fā),同時也為以前的模塊和應用程序提供了更為簡潔的實現(xiàn)方法。本書將會詳細介紹如何利用這個新的拓展架構。新的內核架構讓Apache2成為真正的跨平臺服務器。操作系統(tǒng)層自身成為一個模塊(MPM),使得該模塊可以被各種操作系統(tǒng)裝載。Apache1是一個UNIX應用程序,移植到其他平臺上會受到很多的限制,一些UNIX特性使得Apache1在其他平臺(如Windows和Netware)上性能較差,而Apache2擺脫了這些特性的限制,使其成為一個真正的跨平臺服務器?;诰€程的MPM模塊的引入也增強了UNIX上很多應用程序的可擴展性。Apache2的缺點在于它的API不能向前兼容Apache1,因此一些第三方的模塊和應用程序需要緩慢地升級到Apache2。作為一個穩(wěn)定版本,Apache2.2于2005年12月發(fā)布,相比之前版本具有一些較大的改進。Apache2.2保留并拓展了Apache2.0的API,因此,為Apache2.0所編寫的模塊和應用程序同樣適用于Apache2.2。Apache2.2版本對可擴展性和應用程序架構等方面進行了顯著改進。如果說Apache2.0提供了功能強大的應用平臺基礎,那么Apache2.2則在此基礎上進行了添磚加瓦。Apache軟件基金會Apache軟件基金會(ASF)為一系列應用范圍廣泛的開源軟件項目提供組織上、法律上和財政上的支持。Apache軟件基金會建立了一整套框架來管理知識產(chǎn)權和財政捐獻,同時,限制捐獻者潛在的、合法的資源泄漏。通過精誠合作的項目開發(fā)流程,Apache項目交付了企業(yè)級的、免費獲取的軟件產(chǎn)品,吸引大量的社區(qū)用戶使用。注重實效的Apache許可證(ApacheLicense)使得無論是商業(yè)用戶還是個人用戶都易于部署Apache的產(chǎn)品。Apache軟件基金會的前身是Apache組織(ApacheGroup)。Apache軟件基金會是一個非盈利的組織,基于成員制,以保證Apache項目在個人志愿者參與之外能夠繼續(xù)存在。如果個人承諾與開源軟件開發(fā)項目合作,并不斷地參與和貢獻Apache軟件基金會的項目,那么他(她)就有資格成為Apache軟件基金會的成員。通過Apache基金會現(xiàn)有大部分成員的贊同和任命,個人才能成為軟件基金會的成員。因此,Apache軟件基金會為它所直接服務的社區(qū)所掌控,成員都為社區(qū)內的項目進行協(xié)作。Apache軟件基金會的成員按照基金會的規(guī)章制度,每隔一段時間選舉一個董事會,管理基金會的組織事務,由董事會任命成員監(jiān)管基金會的日常事務。社區(qū)可以公開獲取Apache基金會運作的記錄。功績組織模式(Meritocracy)很多軟件產(chǎn)品都是在一個開放源代碼的許可證之下進行開發(fā)的,ApacheWeb服務器則與此不同°Apache不是由某個開發(fā)者發(fā)起的(而Linux內核、Perl語言和Python語言都是由某個人發(fā)起的),而是一個由各種各樣的人所組成的團隊發(fā)起的,這些人具有相同的興趣愛好,通過交換信息、補丁和各種建議認識彼此。當Apache開發(fā)團隊不再延續(xù)NCSA版本,而是轉向開發(fā)Apache自己的版本時,越來越多的人被這個項目所吸引,加入這個團隊進行開發(fā)。最初,他們可能是發(fā)布一些小的補丁,給出一些開發(fā)建議,或者在郵件列表上回復一些問題,逐步貢獻更多的力量,在開發(fā)中發(fā)揮著越來越重要的作用。當Apache開發(fā)團隊覺得某個人已經(jīng)獲得足夠的權限成為開發(fā)社區(qū)的一部分時,開發(fā)團隊將授予這個人直接訪問代碼倉庫的權限。這個方法不僅能夠擴充團隊力量,增強開發(fā)Apache的能力,而且能夠使開發(fā)團隊運作的效率更高。我們把這個方法稱為功績組織模式。這種模式使得開發(fā)團隊不斷壯大,而且沒有內部矛盾和紛爭。在其他模式下,權利可能是稀缺和保留的資源,而在Apache開發(fā)團隊中,開發(fā)團隊的新成員被看作是希望幫助團隊進行開發(fā)的志愿者,而不是想占據(jù)權位的投機者。同時,由于Apache團隊從不缺乏希望加入的新成員,因此,它不會因為在一個充滿競爭的環(huán)境中缺乏優(yōu)秀人才而盲目地擴充團隊,從而導致開發(fā)團隊成員良莠不齊。相反地,它嚴格對待團隊的每個成員,要求每個成員都具備有據(jù)可尋的貢獻和積極向上的態(tài)度。Apache團隊是一個虛擬社區(qū),因此它是一個全球范圍的社區(qū),不受地域限制。角色Apache開發(fā)團隊具有以下的一些角色。用戶用戶是指使用Apache軟件的人。用戶以缺陷報告和功能建議的形式向Apache項目的開發(fā)人員提供反饋,從而對開發(fā)團隊做出貢獻。用戶也可以參與Apache社區(qū),通過郵件列表和用戶支持論壇幫助其他用戶。開發(fā)者開發(fā)者通過提交代碼和文檔的方式為項目做貢獻。開發(fā)者比用戶的工作要多,他們活躍在開發(fā)郵件列表上,積極參與討論,提供補丁、文檔、建議和批評。開發(fā)人員也被當作是貢獻者。提交者提交人員是開發(fā)者,他被賦予了代碼倉庫的寫權限,并且簽署了貢獻者許可證協(xié)議(Contributor

LicenseAgreement,CLA)。所有的提交者都有的郵件地址。提交者在處理補丁時不需要依靠

其他人,可以獨自做出短期的決定,并服從項目管理委員會(ProjectManagementCommittee,PMC)的監(jiān)項目管理委員會成員項目管理委員會成員是由開發(fā)者或者提交者通過功績選舉產(chǎn)生的,作為其為項目進展所承擔任務的酬勞。項目管理委員會成員具有代碼倉庫的寫權限、的郵件地址、社區(qū)相關決定的投票權,以及建議把某個活躍用戶提升為提交者的權利。項目管理委員會是總體上實施項目控制的實體。Apache軟件基金會成員Apache軟件基金會成員是根據(jù)其在基金會中的角色進展和演變,以及每個角色所取得的功績,由Apache軟件基金會的現(xiàn)有成員選擇并任命的。Apache軟件基金會成員負責管理基金會,如項目相關的核心事務、交叉項目活動等。從法律上來說,Apache軟件基金會成員是基金會的股東之一?;饡蓡T擁有選舉董事會的權利、成為董事會候選人的權利、建議提升某個提交者成為基金會成員的權利,以及廣泛參與基金會內部其他角色的權利。哲學理念盡管這不是官方的列表,但其中的信念已經(jīng)被認為是Apache基金會的核心哲學理念。這些理念有時候被引用為“Apache方法”:協(xié)作化的軟件開發(fā)商業(yè)友好的標準許可證永遠保證高質量的軟件成員之間的交往要互相尊重,誠實,以技術為主依據(jù)標準的忠實實現(xiàn)強制的安全特性Apache開發(fā)流程Apache的開發(fā)流程既可以是自上而下的,也可以是自下而上的。采用自上而下的設計方法時,可以增加一些很棒的想法,如需要代碼重寫或者新的組件所帶來的關鍵新特性、新功能,這些想法可能需要幾個月甚至幾年才能從概念變?yōu)槌墒飚a(chǎn)品。而采用自下而上的設計方法時,可以增加一些小的補丁,用來修改一些軟件Bug或者增加一些新的特性,這些小的補丁很容易融合到目前的軟件版本中。模塊式開發(fā)方法通常介于軟件開發(fā)的宏觀方法和微觀方法之間。模塊是一個自包含的插件,通常是開發(fā)者(大多數(shù)情況下是其他人)基于某種興趣而實現(xiàn)的新特性。一個模塊可能實現(xiàn)了Web服務器的核心功能,也可能實現(xiàn)了一個通用的服務,還可能實現(xiàn)了一個較小但是較為重要的功能,甚至只是一個單一目的的應用。如果某個模塊實現(xiàn)了大家都比較感興趣的功能,而且作者愿意公布,就可以集成到Apache的核心發(fā)布版本中。但是,如果該模塊需要額外的支持(如第三方的庫),或者可能會涉及該模塊的許可甚至是知識產(chǎn)權的因素,那么,該模塊可能就不會被集成到Apache的核心發(fā)布版本中,而是通過它的開發(fā)者或者第三方獨立地發(fā)布,就像支持Apache的公司或者Linux版本的發(fā)行商那么做。Apache代碼倉庫和其他的軟件項目一樣,Apache也維護著一個代碼倉庫。這個代碼倉庫以項目為單位,和Web服務器相關的是httpd項目(包括代碼、文檔和編譯文件)和apr項目。Subversion所有的Apache代碼都保存在代碼倉庫中,可以通過進行訪問。代碼使用SVN進行管理,它是最近(2004年)開始使用的,之前我們使用的是和其功能類似、歷史悠久的CVS系統(tǒng)。代碼倉庫的讀取權限是公開的,但是寫權限只有提交者才擁有。讀權限允許任何人查看Apache開發(fā)過程中所走過的足跡,包括回顧任何單一或者累計的修改,針對這些修改所作的簡要的解釋(例如修改Bug、新的功能、內部改進等),以及修改的日期和參與修改的人員。分支:主線、開發(fā)版本和穩(wěn)定版本代碼倉庫中包含一個主線和幾個分支,其中的任何文件的默認版本都是主線。在Apache項目中,主線代表正在進行中的工作。從定義上可以看出,它是未經(jīng)過測試的版本,一般都包括一些實驗性的代碼。Apache當前的穩(wěn)定分支是Apachehttpd2.2,可以在/branches/2.2.x/目錄下找到。比較老的版本(如2.0和1.3)盡管已經(jīng)不再是主要的開發(fā)方向,但是它們的分支還在維護中(盡管是精簡地維護)。有時候也會為一些實驗代碼特別地創(chuàng)建一些分支,作為測試的基礎。例如,當Apache2.2處于beta版測試時,為了支持異步I/O,需要對內核代碼進行一些實質性的重寫。這些修改后的代碼對于主線來說過于實驗化,因此,開發(fā)者決定創(chuàng)建一個新的開發(fā)分支來處理它們。這個新的分支隨后逐漸地穩(wěn)定下來并融入到主線中,并最終被包含在下一個穩(wěn)定版本(2.4版)中。審查和通過Apache的開發(fā)人員針對穩(wěn)定版本和開發(fā)版本的代碼采用不同的開發(fā)策略進行處理。穩(wěn)定版本的代碼總是遵從審閱并提交的方式(Review-Then-Commit,RTC),這就意味著任何將要加入到標記為穩(wěn)定版本分支的代碼,即使是最微不足道的補丁,也必須通過一個嚴格的審閱過程。開發(fā)版本的代碼遵從提交并審閱的方式(Commit-Then-Review,CTR),這就意味著代碼可能被某個提交者單方面地進行了增加、修改和刪除,然后在恰當?shù)臅r期由其他開發(fā)者進行審閱(當然,SVN使得對某個改變進行逆向操作變得非常容易)。不過,一些主要的變動需要在提交之前就進行審閱,或者使用單獨的開發(fā)分支進行處理。1?3?1.4增加新的功能(backport)新的代碼首先加入主線。如果某個開發(fā)人員想讓這個代碼成為穩(wěn)定分支的一部分(通常是修改了Bug或是做了一點改進),那么這個代碼就將進入backporting階段。該階段使用一個叫做STATUS的狀態(tài)文件,包含了backporting的當前情況列表,如為backport進行的投票情況等。為了保證backporting的質量,代碼的任何變動必須從提交者那里得到至少三張支持票。一張支持票意味著投票人已經(jīng)審閱了這個變動,并對此表示認可,因此,三張支持票就明確意味著這個變動確實不錯即使是最簡單的Bug修改也要遵守這個規(guī)則,這就是說為了得到足夠多提交者的同意,有時候一個不是很重要的Bug修改也得需要很長時間。如果收到了三張支持票并且沒有反對票,這個變動就可以加入到下一個穩(wěn)定分支中了??赡軐忛喠诉@個變動的提交者對此并不滿意,他將對此保留意見,甚至投反對票。投反對票的規(guī)則是必須附帶一個說明,以及(或者)一個能夠實現(xiàn)該變動目標的可選方案。被投了反對票的變動要么被放棄了,要么把其中的錯誤修正之后再次提交進行重新投票。反對票和保留意見通常會在開發(fā)者論壇中進行相關的討論之后被進行處理。發(fā)布Apache有時會發(fā)布新的版本。當前穩(wěn)定代碼版本(在本書正在寫作時為2.2.x版)的發(fā)布使得用戶可以感受到Apache的最新進展,也修改了一些Bug。這些發(fā)布版本將會打上最佳版本的標簽并推薦給用戶。通常由于開發(fā)者覺得已經(jīng)有足夠多的小變動積聚起來了,達到了新版本發(fā)布的要求,這樣一個新的版本就發(fā)布了。不過有時候一個新的版本可能是因為某個安全問題引起開發(fā)者的注意而匆忙發(fā)布的。發(fā)布負責人通常由開發(fā)者志愿擔任,負責管理發(fā)布流程并創(chuàng)建發(fā)布版本,其他的開發(fā)者將會全神貫注于開發(fā)在STATUS文件中已經(jīng)核準的、但還沒有解決的更新,并將其融入到穩(wěn)定版本中。目前的策略是偶數(shù)版本的分支是穩(wěn)定的,而奇數(shù)版本的分支打算供開發(fā)使用。因此2.0.x版本(2002年4月發(fā)布)和2.2.x版本都是穩(wěn)定的,而2.1.x發(fā)布版供Apache2.2版本的alpha測試和beta測試使用。Apache2.1版本經(jīng)過接近10個月的alpha測試和3個月的beta測試之后才成為最終的2.2穩(wěn)定版本。一個發(fā)布版需要在每一個支持的平臺上經(jīng)過編譯、安裝、運行的測試。這些步驟對于穩(wěn)定的發(fā)布版本來說是必需的。對于開發(fā)版本,盡管不是那么嚴格,也是應當如此。為了保證發(fā)布版本滿足這些要求,發(fā)布負責人首先通過一個合適的SVN分支為這個版本創(chuàng)建一個Build版本,然后把這個版本告知Apache的開發(fā)者和測試者。這就在其發(fā)布之前提供足夠的時間,讓更多的開發(fā)者和測試者對其在不同的硬件環(huán)境、操作系統(tǒng)和應用環(huán)境上進行安裝和測試。如果在測試中發(fā)現(xiàn)了一個嚴重問題,那么這個Build版將不被發(fā)布。所有的發(fā)布版本都由發(fā)布管理人進行可靠的PGP簽名。很多Apache開發(fā)者的公鑰,包括所有發(fā)布管理人的,都可以在ht,t,p:///dist,/ht,t,pd/KEY獲得。開發(fā)者論壇ApacheWeb服務器最主要的開發(fā)者論壇就是dev@郵件列表。所有和Apache開發(fā)相關的技術細節(jié)都在這里討論。一個與此類似的開發(fā)者郵件列表dev@是針對APR開發(fā)的。這些論壇都是100%對外開放的,所有的討論都被歸檔在一些地方(本章結尾部分的參考地址)。另外一個比較流行的開發(fā)者論壇是互聯(lián)網(wǎng)中繼聊天(InternetRelayChat,IRC)。關于Apache的開發(fā)者頻道是上的#httpd-dev和#apr。這些討論地點都是完全對外開放的。在/的ApacheBugzilla是一個可以搜索的數(shù)據(jù)庫,包括Bug報告、提升要求和補丁,也包括目前的和歷史的數(shù)據(jù)。這個數(shù)據(jù)庫也是完全對外開放的。不過要注意的是,既然是一個完全開放的數(shù)據(jù)庫,它會含有很多的虛假報告(有些由于不能被結束而顯示為“再次開放”)和不能被驗證真?zhèn)蔚膱蟾???紤]到某些補丁可能對用戶有用,但是這些補丁卻沒有被標準的Apache發(fā)布版包括進來,因此這個數(shù)據(jù)庫也包含了一些故意保留下來的、標記為“補丁可獲取”(PatchAvailable)的報告。包含所有代碼和變動的最完整、最精確的歸檔是位于的Subversion代碼倉庫。這個代碼倉庫隨著代碼的變化而實時地被更新。讀權限是開放和公開的,而寫權限只授予認證過的提交者。在Subversion中值得注意的是STATUS文件和CHANGES文件,前者包括了目前的討論和投票情況,而后者則提供了針對某個穩(wěn)定/發(fā)布版本的變動的執(zhí)行總結。開發(fā)人員Apache很重要的一個特點就是用戶群體的多樣性和開發(fā)群體的多樣性oApache項目不存在由某個公司或者某些公司主導的問題。有些開發(fā)者(包括作者在內)既是一個自由職業(yè)的顧問,也是一個小公司的員工。其他的開發(fā)者有些來自像IBM、RedHat和Novell這樣的大公司,有些來自像Google、Yahoo!和AskJeeves這樣的大型客戶,也有些來自科研院校和其他的非商業(yè)組織。雖然大部分開發(fā)者都是企業(yè)的員工,但是自由職業(yè)者的數(shù)量超過了任何一個公司的人數(shù)。更為重要的是,開發(fā)者的多樣性反映了Apache廣泛的應用范圍。那些超級繁忙的站點(如CNN和HEAnet)需要用24X7的時間承擔成千上萬的并發(fā)用戶負載,主要關注性能、擴展性和穩(wěn)定性;而某些應用站點,例如作者的網(wǎng)站Valet,主要關注如何把Apache從它最初的Web服務器的角色拓展為應用服務器;電子商務網(wǎng)站主要關注安全性和可靠性;主機托管公司需要在維護安全和穩(wěn)定的同時支持需求差異巨大的用戶和代理控制。擁有數(shù)量眾多來自各行各業(yè)的、活躍的開發(fā)者,使得Apache在所有這些應用環(huán)境下都能工作得很好。最后,Apache開發(fā)者社區(qū)決不是一個排外的黑客社區(qū)。盡管軟件開發(fā)和維護是Apache開發(fā)者所有活動中最重要的,但仍然有人在沒有寫過一行C語言代碼的情況下被提拔到Apache組織的高層,因為技術支持、文檔編寫和行政等工作與開發(fā)工作一樣重要。參與Apache工作所有的社區(qū)論壇都是對公眾開放的,這里歡迎任何一個想為Apache貢獻力量的人。有很多種方式可以加入Apache,而每一種工作都很有意義。動手編碼。歡迎為Bugzilla提出的Bug提供補丁。開發(fā)者可在列表上正在爭論的主題或者在STATUS文件中突出強調的主題做出貢獻。如果某位開發(fā)者想加入工作,可以到位于SVN的代碼倉庫中搜索TODO記錄和FIXME記錄。如果一個補丁能夠干凈地集成(通過diff-u或者svn-diff方式),并且有比較清晰的動機和功能描述,那么這個補丁是受歡迎的。補丁便可以通過開發(fā)者列表或Bugzilla發(fā)布。撰寫文檔。文檔存放在SVN中。所有的原始文檔都是XML格式的,該格式是DocBook的一個子集。歡迎撰寫新的文檔,或者對原有的文檔進行修訂(添加補?。?。文檔翻譯。文檔一般都具有多個語言的版本。但不是文檔中每一頁都具有不同語言的版本,而且文檔的翻譯版本也不一定都是最新的。因此如果你具有語言天賦,那么就去找到缺失的或者過時的文檔并修正它們吧。測試軟件。在你的平臺上構建并測試代碼,特別是當你具有一個與眾不同的平臺時。使用不尋常的環(huán)境和工具構建Apache,它能夠干凈地構建和安裝嗎?可以使用你所有不尋常的任務對它進行壓力測試。如果它失敗了,或者你發(fā)現(xiàn)它相對于之前的版本有一個意想不到的變化,試著去診斷究竟發(fā)生了什么。把你找到的任何Bug都通過開發(fā)者列表和Bugzilla報告出來。努力保證你所描述的情況是清晰明了并且可重現(xiàn)的。構建軟件。維護Apache的構建和安裝是一個很重要的任務,但是直到本書寫作為止我們都沒有很好地處理它。即使是在UNIX/Linux家族平臺上最廣泛使用的GNU基于自動配置的安裝,檢查一下都是有好處的。1.4Apache和知識產(chǎn)權所有的Apache項目的版權都歸Apache軟件基金會所有,并使用Apache許可證進行許可。同時,Apache軟件基金會和項目管理委員會采用各種方法來保證當沒有合法綁定時,Apache的代碼中不包含第三方的有知識產(chǎn)權的代碼,并且用來發(fā)布的寫權限處于Apache許可證的保護之下。不過,值得注意的是,雖然Apache掌握一個項目的整體版權,但是項目中某個部分的版權可能歸個人貢獻者所有,并基于Apache軟件基金會的條款進行許可。Apache許可證Apache許可證(可以在附錄A中找到)是一個自由的軟件許可證,基于傳統(tǒng)的BSD和MIT軟件許可證,增加了適合我們時代要求的一些重要條款。它滿足自由軟件和開源軟件所有已經(jīng)被接受的定義??赡茏杂绍浖男g語讓一些讀者感到迷惑,我們暫且對其中的某些重要部分進行澄清。值得注意的是,這只是一些基本的背景信息,可能對任何一個特定國家的讀者來說不是法律忠告。自由的言論,不是免費啤酒免費的啤酒是美妙的,但是自由的言論更加重要。當我們談到軟件自由時,一般都會有自由言論的感覺。軟件自由主要體現(xiàn)在任何人都有想做什么就做什么的自由(當然,可以自己去做,也可以雇人去做)。源代碼開放也是軟件自由的一個必要組成部分。價格和軟件自由不相關。Apache可以通過各種價格獲得,從免費的下載,到捆綁在一個商業(yè)Linux版本的軟件包,甚至是由商業(yè)組織開發(fā)的全額軟件產(chǎn)品。非公開領域和其他很多自由軟件類似,Apache不是一個公開領域。Apache的版權為Apache軟件基金會所擁有,并具有許可證。和那些商業(yè)軟件的許可證相比,Apache的許可證顯得更加友好,并且沒有那么多的限制。不是共享軟件和廣告軟件共享軟件(包括Nagware、廣告軟件等)概念上和自由軟件類似。它們通常(盡管不是全部)都被認為是質量較差的、比較業(yè)余的產(chǎn)品,如今通常都是受商業(yè)驅使開發(fā),而不是受技術驅使。不是GPL由自由軟件基金會(FreeSoftwareFoundation)編寫并擁有的GNU通用公眾許可證GPL(GeneralPublicLicense),是最老的也是最廣為人知的(同時也是最誤傳的)自由軟件許可證。GPL引入的一個概念稱為copyleft(和copyright對應),它的基本理念可以總結如下:“我們授予你這些自由,而你不能把這些自由從其他人手里拿走?!边@個策略有時候被認為是商業(yè)不友好的,因為copyleft軟件不管愿意不愿意,是不能被融入到非自由軟件中的。Apache許可證明顯是商業(yè)友好的,它不是copyleft。事實上,Apache許可證甚至和GPL是互不兼容的。這是因為每一個許可證都有一些規(guī)定,這些規(guī)定和其他的許可證是互不兼容的:GPL軟件使用Apache軟件基金會條款進行發(fā)布,因為copyleft的限制導致和Apache軟件基金會策略不兼容。Apache軟件基金會許可的軟件也不能使用GPL條款進行發(fā)布。關于這個問題我們可以看看自由軟件基金會是如何說明的:Apache許可證是一個自由軟件許可證,但是它和GPL不兼容。Apache許可證之所以和GPL不兼容是因為它具有一個特別的要求,而GPL沒有:它具有一些專利終止的情況,而GPL不需要。(我們不認為具有這些專利終止情況就不好,但是它們和GNU的GPL不兼容。)但是這些因素對于終端用戶和第三方(如模塊開發(fā)者或發(fā)布者)來說并不是問題。Linux(GPL)廠商例行公事地在他們的產(chǎn)品中包括了Apache,也有很多的Apache模塊是GPL許可的。Linux發(fā)布者同時遵守兩種許可,模塊開發(fā)者為他們的工作選擇遵從某個許可,這些都沒有問題。即使是最崇尚單一的、對法律最小心翼翼的Debian發(fā)布版本也為Apache發(fā)布了GPL的模塊。當和GPL軟件進行接口時,許可的不兼容會導致一些問題。以MySQL的實現(xiàn)為例,MySQL是一個GPL許可下的SQL數(shù)據(jù)庫軟件包,為了遵從MySQL的GPL許可要求,MySQL的Apache/APR驅動也是GPL許可的,因此不能被ASF集成在Apache中進行發(fā)布。作為替代選擇,它可以從其作者的網(wǎng)站上進行單獨下載,或者從第三方作為一個單獨的軟件包獲取。這就只和自己編譯Apache的用戶相關,而那些使用軟件包安裝的用戶就永遠不需要關注這些細節(jié)問題。專利和反強盜條款對于技術開發(fā)者來說,當今最大的危險就來自于專利,這種情況在美國尤為突出。在美國,專利系統(tǒng)一直被看作是維護經(jīng)濟壟斷的工具:為“我們”的公司申請成千上萬的專利,然后通過世界貿易組織(WorldTradeOrganization,WTO)的條約將這些專利執(zhí)行,以期獲得全球競爭優(yōu)勢。結果就是,美國的專利局要處理大量的專利事務,導致沒有辦法對每個專利進行詳細審查和質量控制。很多這樣的專利就掌握在對技術沒有絲毫興趣的人手上,他們期望從合法的商業(yè)中勒索錢財。切實的感受就是:這就是當今的強盜。在過去,某個國家、省或者城市的統(tǒng)治者會為“他們的”海進行圈地聲明,向每一個經(jīng)過他們領地的外來船只收取一定數(shù)量的過路費,并且允許私掠船(戰(zhàn)時特準攻擊敵方商船)保護他們的財產(chǎn)權利,查封任何經(jīng)過而沒交費的船只。類似的,如今的專利持有人向合法的商業(yè)索取費用,雇傭律師來強化他們的財產(chǎn)。事實上,如今的這種強盜行徑比過去更為惡劣:如今專利的數(shù)量比過去海上的強盜數(shù)目多得多,也不再存在安全的航線了。Apache許可證的一個非同尋常的限制就是盡可能地處理這種情況。接受Apache的許可意味著不能有任何反對Apache軟件基金會和Apache用戶的專利權限。據(jù)我所知,Apache從沒有卷入到知識產(chǎn)權的法律案件中。這和在SCO案件中Linux面臨的情況形成了鮮明的對比(盡管看起來Linux很可能會辯護成功),更不用提和微軟所面臨情況的對比:微軟的用戶已經(jīng)為微軟軟件中由于違反專利而向第三方支付了大量的補償,。第三方知識產(chǎn)權Apache的知識產(chǎn)權通過版權和許可證進行保護。當然,Apache也不會侵犯其他人的知識產(chǎn)權,這點也很重要。這就意味著所有對Apache的重要貢獻都必須使用正確的方式進行捐贈。在一個開發(fā)人員成為提交者之前,他(她)必須簽署一份貢獻者許可協(xié)議(ContributorLicenseAgreement,CLA),使得Apache軟件基金會被授予所有必需的權利來使用這個開發(fā)者的貢獻,并將其通過Apache軟件基金會條款向第三方進行許可。貢獻者許可協(xié)議使得開發(fā)者在加入Apache之前,限制他們承認所有的貢獻不是他們自己的原創(chuàng)工作,而是簽字移交給Apache。貢獻者許可協(xié)議的全文可以參考附錄B。如果一個開發(fā)者自己不能決定(例如,一個雇員的雇主可能對他或她的工作擁有權利)時,需要該開發(fā)者的授權上級領導(例如,首席技術官或者IT主管)簽發(fā)一個企業(yè)貢獻者許可協(xié)議(CorporateCLA,CCLA),企業(yè)貢獻者許可協(xié)議的全文可以參考附錄B。在開發(fā)者可以被授予提交訪問權限之前,所有的貢獻者許可協(xié)議、企業(yè)貢獻者許可協(xié)議必須形成文檔并保留在Apache軟件基金會。這些協(xié)議被用來保證提交者和他們的雇主不能阻止Apache軟件基金會或Apache的用戶使用他們的貢獻。職責首先,每一個提交者都必須保證他(她)的貢獻沒有侵犯第三方的知識產(chǎn)權,這是他們的職責。全面的職責是屬于項目管理委員會的,它將質疑任何出現(xiàn)可疑情況的貢獻,特別是主要的新貢獻。審計盡管所有都考慮到了,仍然可能出現(xiàn)第三方知識產(chǎn)權的問題。Apache有一條完整的審計鏈,由Subversion管理。因此,即使在最壞的情況下,任何有問題的代碼都可以被查出來并刪除。交互式在線論壇公共郵件列表Apache模塊開發(fā)者列表modules-dev@httpd.apache.or是一個討論任何和模塊開發(fā)相關問題的好地方。這個列表在2006年9月移到apache-modules@covalent.ne,t因此可以查看這兩個列表上的資料。ApacheWeb服務器的官方開發(fā)者列表是dev@歡迎大家參與,不過請不要離題。Apache可移植運行時庫(ApachePortableRuntime,APR)的官方開發(fā)者列表是dev@歡迎大家參與,不過請不要離題。Apache的用戶列表是users@httpd.apache.or,g是一個討論各種問題和進行用戶支持的論壇。用戶組systems.www.servers[unix|windows|mac|mis]新聞組是一個對不同平臺上Apache的各種問題進行討論的好地方。在線交談在irc://irc.freenode.ne上有幾個頻道和Apache相關。#apache:通用支持/非官方的幫助臺頻道??梢詥栆恍┯幸饬x的問題并等待答案。但是首先你必須做功課,特別是要看錯誤日志。注意fajita,它是#apache的機器人程序,它將做很多的常規(guī)工作如回答你的問題,或者貼出一些相關的文檔頁面地址。#apache-modules針對模塊開發(fā)的頻道。這個頻道非常適合本書的讀者。#apr:APR半官方的頻道,包括自動的、對APR代碼倉庫變動的實時通告。#httpd-dev:Web服務器開發(fā)的半官方頻道,包括自動的、對代碼倉庫變動的實時通告,以及文檔和網(wǎng)站。#asfinfra:Apache的架構頻道。會議Apache軟件基金會為專注于Apache軟件基金會項目的開發(fā)者組織了ApacheCon會議。這些會議將很多的開發(fā)人員聚集到一起(這些開發(fā)人員在網(wǎng)上論壇中互相都比較熟悉,但是他們中間很多人都不曾面對面相聚過)。用戶也許只是過來學習的,但是他們有時也會給開發(fā)者帶來一些新的見解。會上有開發(fā)者和用戶共同參與的教程和報告,可能是官方組織的,也可能是非正式的社會事務,安排得非常緊湊。網(wǎng)站官方和半官方的Apache網(wǎng)站/Apache軟件基金會/ApacheWeb月服務器http://apr.apa,/APR主站/Apache代碼倉庫/Bug數(shù)據(jù)庫/Apache模塊注冊/modules/更新的模塊注冊(正在建設中)http://mail—/由E件歹U表文檔/Apache提交者的個人主頁/ApacheCon會議/mod_perl/(Apache的PerlAPI)/mod_python(Apache的PythonAPI)/Apache中的TCL語言/cli/mod_aspdotnet(微軟的ASP.Net)第三方擴展/筆者所編寫的20多個模塊http://www.outoforder.cc/其他工作的12個有特色的模塊/PHP語言/RubyonRails開發(fā)者文檔/API參考http://www.apachetutor,org/dev/筆者創(chuàng)建和維護的開發(fā)者教程http://dev.ariel—/apr/aptutorial/html/aptutorial.ht針對APR的有用教程,將它的角色從Web服務器中剝離出來http://www.apache—modules.qm/本書的官方網(wǎng)站,還沒有完成其他的教程、新聞和文章/pub/q/all_apache_article丈量的文章http:///新聞網(wǎng)站,也是Windows二進制程序的下載站點(通常比“官方”要早一些發(fā)布)http://marc.theaimsgroup.郵件列表文檔1.6小結本章介紹了Apache的社會背景、歷史背景和法律背景,以及Apache的文化。第1章特別介紹了以下幾個方面:Apachehttpd的發(fā)展歷史Apache軟件基金會和它的文化Apache的開發(fā)者、流程、開發(fā)和技術支持的資源,包括如何參與ApacheApache對待知識產(chǎn)權的方法,包括Apache許可證和避免誤用第三方知識產(chǎn)權的安全機制第1章是與技術無關的,而本書后續(xù)部分將全部是關于Apache開發(fā)的。本書以容易理解的概述開始,然后將轉向對模塊和應用程序開發(fā)進行實際操作訓練。Apache作為常駐的后臺任務運行:在UNIX系統(tǒng)中為守候進程(Daemon),在Windows系統(tǒng)中為服務(Service)。由于Apache服務器的啟動階段比較耗費時間和資源,因此它一般在操作系統(tǒng)啟動時被啟動并一直運行。Apache的早期版本曾支持inetd模式,但是該模式已經(jīng)不再適合實際的應用??v覽Apache的HTTP服務器由一個相對較小的內核及一些模塊組成,如圖2.1所示。模塊可以靜態(tài)的編譯到服務器中,但是通常都把模塊放在/Modules/目錄或者/libexec/目錄下面,服務器運行時這些模塊被動態(tài)加載。另外,Apache服務器依賴底層的可移植運行時庫(ApachePortableRuntime,APR)??梢浦策\行時庫提供跨平臺的操作系統(tǒng)抽象層和功能函數(shù),為上層模塊提供統(tǒng)一的接口,這樣模塊可以避免受到不可移植的操作系統(tǒng)調用的影響。多處理模塊(Multi-ProcessingModule,MPM)是一個特殊的功能模塊,用來根據(jù)底層的操作系統(tǒng)來優(yōu)化Apache。多處理模塊通常是唯一直接訪問操作系統(tǒng)的模塊,其他模塊可以通過可移植運行時庫來訪問操作系統(tǒng)。圖2.1Apache架構Apache運行的兩個階段Apache的運行分為啟動階段和運行階段。啟動階段時,Apache以特權用戶root啟動,進行解析配置文件、加載模塊和初始化一些系統(tǒng)資源(例如日志文件、共享內存段、數(shù)據(jù)庫連接)等操作。處于運行階段時,Apache放棄特權用戶級別,使用非特權用戶來接收和處理網(wǎng)絡中用戶的服務請求。這種基本安全機制可以阻止Apache中由于一個簡單軟件錯誤(也可能是模塊或腳本)而導致的嚴重系統(tǒng)安全漏洞,例如微軟的IIS就曾遭受“紅色代碼(CodeRed)”和“尼姆達(Nimda)”等惡意代碼的溢出攻擊。Apache的這種兩個階段的運行方式對應用程序的架構具有一定影響。首先,任何需要系統(tǒng)級權限的操作都必須在系統(tǒng)啟動時運行。其次,最好在啟動階段進行盡可能多的初始化工作來簡化處理每個請求時的工作量。這樣做帶來的影響就是:由于耗費很多時間和資源的操作都集中在啟動階段完成,因此Apache以inetd或tcpserver模式運行時效率就會非常低。Apache的架構有一個不符合常規(guī)的古怪之處:配置代碼實際上在啟動階段執(zhí)行了兩次(盡管不是重新啟動)。第一次,檢查服務器配置是否正確(至少,Apache能夠成功啟動);第二次是真正的系統(tǒng)啟動,然后引導至運行階段。這種啟動執(zhí)行兩次的行為大多數(shù)模塊都能忽略(如APR池能夠保證不會引起資源的泄漏),但是,對某些模塊還是有影響的。例如,某些模塊在系統(tǒng)啟動階段動態(tài)加載新的代碼,如果想要這些代碼只加載一次,那么就需要采用某些技巧(例如采用檢查全局標志位的方法)來保證加載操作只做了一次。啟動階段Apache在啟動階段讀取配置文件、加載模塊和函數(shù)庫,以及分配資源。每個模塊可能都需要資源,并在啟動階段對這些資源進行初始化。Apache在啟動階段擁有系統(tǒng)最高權限,以單進程、單線程方式運行。配置Apache的主配置文件通常為httpd.conf。但是由于這種命名方式為一般慣例,并非強制要求,因此提供.rpm或者.deb包的第三方,Apache發(fā)行版本可能使用不同的命名機制。另外,httpd.conf文件可能是單一文件,也可能是通過使用Include指令包含不同配置文件的多個文件集合。有些發(fā)行版本的配置非常復雜。例如DebianGNU/Linux的Apache配置需要對Debian非常熟悉而不是Apache。本書并不探討不同配置設計的優(yōu)缺點,因此,為了簡化,我們認為配置文件為httpd.conf。httpd.conf文件是一個文本文件,在系統(tǒng)啟動時被逐行解析。該文件由指令、容器和注釋組成。配置文件內允許有空行和空格,它們在解析時被忽略不計。指令(Directives)httpd.conf文件中大多數(shù)內容是指令。指令可以沒有參數(shù),也可以有多個參數(shù),參數(shù)之間用空格隔開。每一個指令有自己的語法格式,不同的指令允許不同的參數(shù)個數(shù)和參數(shù)類型(有字符串、數(shù)字、枚舉、布爾或文件名等)。指令是在內核或者一些模塊中實現(xiàn)的,我們將在第9章中介紹。以下是幾個指令的實例。LoadModulefoo_modulemodules/mod_foo.so這個指令由mod_so模塊實現(xiàn),用來加載一個模塊。第一個參數(shù)是模塊名(字符與數(shù)字組成的字符串),第二個參數(shù)是文件名,可以是服務器根目錄的絕對路徑或者相對路徑。DocumentRoot/usr/local/Apache/htdocs這個指令由內核實現(xiàn)的,用來設置網(wǎng)頁所在主文檔樹的根目錄。SetEnvhello“Hello,World!這個指令由mod_env模塊實現(xiàn),用設置環(huán)境變量。注意,由于第二個參數(shù)包含空格,我們必須用雙引號把它包含起來。ChoicesOn這個指令由mod_choices(將在第6章介紹)實現(xiàn),用來激活模塊的選項。容器(Containers)容器是一系列指令的集合,語法和標記語言很相像,使用尖括號進行歸類。容器在語義上和其他指令不同,具有一個開始和結束的分隔行,在分隔行之間的指令為容器內部的指令。例如由內核模塊中的〈VirtualHost〉容器如下所示,該容器定義了一個虛擬主機。<VirtualHost39>ServerNameDocumentRoot/usr/www/exampleServerAdminWebma.ster@CustomLog/var/log/www/example.log〈/VirtualHost〉容器為里面的指令提供了上下文。在上面這個例子中,指令只對訪問www.example.co的請求進行響應。容器可以被嵌套使用,除非某個模塊顯式地聲明容器不能嵌套。所有用到的指令,包括容器,都可能是上下文相關的,因此它們在某些具體的上下文中才有效。注釋(Comments)如果一行語句以#號開頭,那么該行被認為是注釋語句。例如下面的語句為注釋。#thislineisacomment行中的#一般不會被認為是注釋,除非模塊明確地在實現(xiàn)該指令時支持行中注釋。如果模塊沒有被加載,那么該模塊所實現(xiàn)的指令就不能被識別。遇到這種情況時,Apache執(zhí)行停止并返回一個語法錯誤。因此mod_so模塊必須用靜態(tài)的方式進行鏈接來加載其他模塊。這一點非常重要!當你開發(fā)新的模塊時沒有靜態(tài)地鏈接mod.so,那么每次在修正該模塊時必須重新編譯整個服務器程序。運行階段在啟動階段末期,程序的控制轉向多處理模塊MPM(見2.3節(jié))。MPM模塊在系統(tǒng)級管理Apache的運行。它根據(jù)操作系統(tǒng)和應用的約束(如一些特殊場景的應用)維護進程池和/或線程池。MPM的進程作為控制者,管理一系列子工作進程。子工作進程用來處理接入請求,而控制者進程負責創(chuàng)建和刪除子工作進程以及處理信號量(如停止或者重啟)。MPM的架構導致不可能在有限的的范圍內描述運行階段。盡管標準的MPM采用工作子進程的方式,但是MPM并沒有被限制只能使用這一種方式。理論上MPM可以在系統(tǒng)層上實現(xiàn)其他完全不同的服務器架構。停止階段雖然沒有明確的停止階段,但是需要在服務停止的時候完成的工作應被注冊為清除操作(在第3章中介紹)。當Apache停止的時候,所有注冊的清除操作都將運行。多處理模塊MPM在啟動階段的末期,當所有的配置信息被讀取之后,Apache的控制轉到多處理模塊MPM°MPM提供Apache服務程序和其所在的操作系統(tǒng)之間的接口。該模塊的主要職責是根據(jù)所在的操作系統(tǒng)平臺來優(yōu)化Apache,提高Apache的效率,保證Apache的安全。MPM自身也是一個模塊,這點我們能夠從它的命名看出。值得注意的是,MPM是Apache中唯一的一個系統(tǒng)層模塊(因此開發(fā)MPM已經(jīng)超出本書關于應用程序開發(fā)的范圍)。同樣一個Apache實例只能有一個在編譯時所選擇的MPM。為什么需要MPM老版本的NCSAserver和Apache1是在UNIX系統(tǒng)中成長起來的。當時Apache是一個多進程服務器,一個服務進程處理一個用戶請求,如果當前并發(fā)客戶訪問數(shù)量大于服務進程數(shù),Apache便會增加新的服務進程來處理當前請求。在正常情況下,Apache會維護一定數(shù)量的服務進程來處理用戶的請求。盡管這種多進程服務機制在Unix類系統(tǒng)中能夠很好地工作,但是在其他的平臺上效率卻很低,如在Windows中產(chǎn)生一個進程是非常費時的。因此,讓Apache真正實現(xiàn)跨平臺還需要其他的方法。Apache2采用的方法是把核心任務處理作為一個可插拔的模塊,即MPM,使其能針對不同的環(huán)境進行優(yōu)化。MPM架構允許不同的Apache模塊在一個操作系統(tǒng)平臺下共存,能夠為用戶根據(jù)不同應用做出選擇。在實際應用中,只有UNIX類操作系統(tǒng)有其他的選擇,而其他系統(tǒng)平臺(Windows、Netware、OS/2、BeOS)則只有唯一的根據(jù)操作系統(tǒng)優(yōu)化的MPM。在UNIX平臺上,Apache2.2目前已經(jīng)有兩種高質量的、作為標準的MPM(Prefork和Worker),第三種(Eevent方式)在不使用SSL的情況下也是穩(wěn)定可靠的。另外還有一些MPM可以實驗應用,暫時不適合產(chǎn)品應用。其他第三方的MPM模塊也是可用的。UNIX類的MPM模塊PreforkMPM基于非線程模型,和Apache1.x版本中的MPM很相似。PreforkMPM在所有情況下都很安全,對運行非線程安全(non-thread-safe)模式的軟件如PHP,它是唯一的安全選擇。對于某些應用程序,包括在Apache1.3上非常流行的程序(如簡單靜態(tài)頁面、CGI腳本等),PreforkMPM是最好的選擇。WorkerMPM基于線程模式,具有內存消耗低(對繁忙的服務很重要)、擴展性在某些特定應用情況下比Prefork更好等優(yōu)點。在稍后介紹SQL數(shù)據(jù)庫支持和mod_dbd模塊時我們會討論其中一些內容。以上兩種穩(wěn)定的MPM方式在非常繁忙的服務器應用下都有些不足。盡管HTTP的Keepalive方式能減少TCP連接數(shù)量和網(wǎng)絡負載,但是Keepalive需要和服務進程或者線程綁定,這就導致一個繁忙的服務器會耗光所有的線程。EventMPM是解決這個問題的一種新模型,它把服務進程從連接中分離出來。在服務器處理速度很快,同時具有非常高的點擊率時,可用的線程數(shù)量就是關鍵的資源限制,此時EventMPM方式是最有效的。一個以WorkerMPM方式工作的繁忙服務器能夠承受每秒好幾萬次的訪問量(例如在大型新聞服務站點的高峰時),而EventMPM可以用來處理更高負載。值得注意的是,EventMPM不能在安全HTTP(HTTPS)訪問下工作。還有一些針對UNIX系統(tǒng)的、處于實驗中的MPM,在本書編寫過程中,它們在繼續(xù)開發(fā),有的可能已經(jīng)實現(xiàn)了。PerchildMPM具有一個非常好的特性:以不用的用戶ID為不同的虛擬主機運行Apache服務器。其他的一些MPM也提供類似的功能,包括第三方的Metux和Peruser,以及mod_ruid(只支持Linux)。為了運行外部程序,還可選擇fastcgi/mod_fcgid和suexec(CGI)。作者對第三方的解決方案沒有相應的了解,因此不能作出相應的評價。MPM模塊和操作系統(tǒng)一言以蔽之:對應用程序來說,MPM方式很少見,應該忽略!既然MPM內部機制不是應用程序接口的一部分,Apache的應用開發(fā)者不需要知道MPM的細節(jié)。這里就簡單帶過。一些為應用開發(fā)者提供的最佳實踐的基本規(guī)則(命名機制、編寫安全線程、交叉進程安全、代碼重入)將會在第4章中簡單介紹。這里主要介紹開發(fā)平臺無關代碼。事實上,有時應用程序的開發(fā)平臺更要考慮MPM而不是操作系統(tǒng)。有時一個應用程序更加適應于某個MPM。例如,數(shù)據(jù)庫驅動或者負載均衡應用程序得益于threadMPM方式的連接池(在本書稍后討論)。反之,產(chǎn)生子進程(原始的CGI實現(xiàn)或者mod_ext_filter)在一個基于線程的程序中會產(chǎn)生巨大開銷,因此在PreforkMPM方式下工作得更好。然而,除非某些特殊限制,應用程序應該考慮如何適應在非首選的MPM下工作。如果你想讓Apache運行在現(xiàn)在還不支持Apache的操作系統(tǒng)上,那么首要的任務是在APR庫中增加對目標平臺的支持。APR庫用來提供操作系統(tǒng)層的支持。一個定制的MPM不是必需的,但是它很可能比已有的MPM提供更好的性能。從Apache的角度出發(fā),這是一個系統(tǒng)編程的任務,因此它已經(jīng)超出一本應用程序開發(fā)書籍的介紹范圍?;靖拍詈蛿?shù)據(jù)結構要想在Apache平臺上做開發(fā),我們需要對Web服務器運行的基本單元和Apache的內核結構有大致的了解。其中最重要的概念是服務器、TCP連接和HTTP請求。進程作為Apache中第4個基本對象,是操作系統(tǒng)的一個執(zhí)行單元,而不屬于應用程序架構。每一個基本單元由一個在httpd.h頭文件中定義的內核數(shù)據(jù)結構表示。與在應用程序開發(fā)中我們遇到的其他內核對象一樣,這些基本單元在應用時和MPM無關。在描述這些內核數(shù)據(jù)結構之前,我們需要介紹貫穿在整個Apache當中并且和體系結構緊密關聯(lián)的概念。APR池(apr_pool_t)是Apache中資源管理的核心。當一個資源被動態(tài)分配時,在APR池中注冊一個清理操作,保證資源在不再需要的時候能夠被釋放掉。APR池將資源綁定到一個內核對象的生命周期當中。我們將在第3章中深入討論APR池。配置記錄被每一個模塊用來將自己的數(shù)據(jù)綁定到一個內核對象中。內核數(shù)據(jù)結構包含配置向量(ap_conf_vector_t)。每一個模塊在配置向量中有自己的入口。配置向量有兩種用途:一是設置和獲取全局的配置數(shù)據(jù);二是將臨時數(shù)據(jù)保存到臨時的對象中。在一個模塊中應該盡量避免使用不安全的靜態(tài)變量和全局變量,這點將在第4章和第9章中討論。在介紹完APR池和配置數(shù)據(jù)之后,我們接下來看Apache的內核對象。按照對模塊的重要性排列,它們是:request_recserver_recconn_recprocess_rec在應用程序開發(fā)中,前兩種對象是經(jīng)常遇到的。request_recrequest_rec對象在Apache接受連接請求的時候創(chuàng)建,并在處理完請求之后馬上銷毀。為了處理連接請求(在第5章和第6章中討論),request_rec對象被傳遞給所有模塊的處理例程句柄。request_rec對象擁有所有涉及處理該HTTP請求的內部數(shù)據(jù),也包括Apache用來維護中間狀態(tài)和客戶端信息的一系列字段。管理在處理請求周期中的對象的請求池。用來管理在處理請求期間的資源分配。靜態(tài)請求配置(在httpd.conf或者.htaccess中指定的目錄訪問權限)的配置記錄向量。處理請求過程中用來管理臨時數(shù)據(jù)的配置記錄向量。HTTP輸入報頭表,輸出報頭表和錯誤信息報頭表。以及一個類似的記Apache環(huán)境變量表(SSI、CGI、mod_rewrite、PHP腳本處理擴展中用到的環(huán)境變量),以及一個類似的記錄請求數(shù)據(jù)的表,該表對腳本不可見。指向其他相關對象的指針。包括connection、server和任何一個相關的請求對象。指向輸入輸出過濾鏈(在第8章中討論)。URI請求及其中間解析形式,包括處理例程(見第5章)和文件系統(tǒng)映射(見第6章)這是摘自于httpd.h文件中對request_rec對象的完整定義:/**表示當前請求的結構*/structrequest_rec{/**和該請求相關聯(lián)的池*/apr_pool_t*pool;/**到客戶端的連接*/conn_rec*connection;/**處理本連接的虛擬主機*/server_rec*server;/**如果有外部重定向,指向請求重定向的指針*/request_rec*next;/**如果是內部重定向,指向前一個請求的指針*/request_rec*prev;/**如果是一個子請求,指向主請求的指針*(參見http_request.h)*/request_rec*main;/*請求自身的信息...我們從protocol.c能夠涉及的項開始*//**請求的第一行*/char*the_request;/**HTTP/0.9,簡單的請求(例如,GET/foo\nw/noheaders)*/intassbackwards;/**一個代理請求(在post_read_request/translate_name過程中計算)可能的值有:PROXYREQ_NONE、PROXYREQ_PROXY、PROXYREQ_REVERSE、PROXYREQ_RESPONSE*/intproxyreq;/**HEAD請求,和GET相反*/intheader_only;/**協(xié)議字符串,我們可以指定,或者為HTTP/0.9*/char*protocol;/**協(xié)議的版本號;1.1=1001*/intproto_num;/**主機,使用URI或者Host設定*/constchar*hostname;/**請求開始的時間*/apr_time_trequest_time;/**狀態(tài)行,如果被腳本設定*/constchar*status_line;/**狀態(tài)行*/intstatus;/*請求的方法,雙向的;在protocol.c的外面,*只參考,不要修改。*//**請求的方法(例如GET、HEAD、POST等)*/constchar*method;/**M_GET、M_POST等*/intmethod_number;/**“allowed”是一個允許方法的位向量。*處理函數(shù)必須保證請求方法是可以被處理的。任何模塊應當拒絕它們不能處理的任何請求方法。*在終止處理函數(shù)之前,處理函數(shù)應當為每一個它愿意處理的請求方法設置r-〉allowed。這個位向量用來確認"Allow"OPTIONS請求、HTTP_METHOD_NOT_ALLOWED、HTTP_NOT_IMPLEMENTED狀態(tài)碼。**既然默認的處理函數(shù)處理OPTIONS,那么其他的模塊一般拒絕處理OPTIONSo*TRACE總是“Allowed”。模塊不需要顯式地設置它。**既然默認的處理函數(shù)總是處理GET,那么*一個沒有實現(xiàn)GET的模塊可以返回HTTP_METHOD_NOT_ALLOWED,*不過這也意味著一個腳本GET處理函數(shù)不能被mod_actions安裝。*/apr_int64_tallowed;/**擴展方法的數(shù)組*/apr_array_header_t*allowed_xmethods;/**允許方法的鏈表*/ap_method_list_t*allowed_methods;/**body數(shù)據(jù)流的字節(jié)數(shù)*/apr_off_tsent_bodyct;/**body的字節(jié)數(shù)*/apr_off_tbytes_sent;/**請求資源的最后修改時間*/apr_time_tmtime;/*HTTP/1.1連接層的性質*//**發(fā)送塊的傳送代碼*/intchunked;/**Range:header*/constchar*range;/**“真正”的內容長度*/apr_off_tclength;/**從請求主體中讀取剩余的字節(jié)數(shù)*/apr_off_tremaining;/**從請求主體中已經(jīng)讀取的字節(jié)數(shù)*/apr_off_tread_length;/**讀取請求主體的方法。(例如REQUEST_CHUNKED_ERROR、REQUEST_NO_BODY、REQUEST_CHUNKED_DECHUNK等)*/intread_body;/**讀取塊的傳送代碼*/intread_chunked;/**客戶端等待100個回復?*/unsignedexpecting_100;/*輸入和輸出的MIME報頭環(huán)境,以及一個發(fā)送給子過程的、包含環(huán)境變量的數(shù)組。*所以人們可以編寫模塊增加到這個環(huán)境中。**headers_out和err_headers_out的區(qū)別在于err_headers_out在發(fā)生錯誤時也被*顯示。*并且在內部重定向時被保留*(因此為ErrorDocument處理函數(shù)所顯示的header會有這些內容)。constchar*handler;constchar*handler;/*我們真正用來處理命令的函數(shù)*/constchar*handler;constchar*handler;/*我們真正用來處理命令的函數(shù)*/*'notes'apr_table_t被用來從一個模塊向另一個模塊記錄,沒有其他的意圖。*//**請求的MIME報頭環(huán)境*/apr_table_t*headers_in;/**應答的MIME報頭環(huán)境*/apr_table_t*headers_out;/**應答的MIME報頭環(huán)境,在出現(xiàn)錯誤時被顯示,并且在內部重定向中被保留*/apr_table_t*err_headers_out;/**為子過程所使用的環(huán)境變量數(shù)組*/apr_table_t*subprocess_env;/**一個模塊到另一個模塊的記錄*/apr_table_t*notes;/*content_type、handler、content_encoding和所有的content_languages*必須是小寫字母的字符串。它們可以是指向靜態(tài)字符串的指針,*不能被修改。*//**當前請求的content-type*/constchar*content_type;/**用來調用一個處理函數(shù)的函數(shù)名稱*//**如何編碼數(shù)據(jù)*/constchar*content_encoding;/**表示內容語言的字符串數(shù)組*/apr_array_header_t*content_languages;/**變長列表驗證器(如果協(xié)商)*/char*vlist_validator;/**如果通過認證檢查,用來設定用戶名*/char*user;/**如果通過認證檢查,用來設定認證類別*/char*ap_auth_type;/**表示不能被緩存*/intno_cache;/**沒有此應答的本地拷貝*/intno_local_copy;/*需要什么樣的對象(可以是直接的,也可是內容協(xié)商映射的)*//**沒有經(jīng)過分解的URI*/char*unparsed_uri;/**URI的路徑部分*/char*uri;/**和此應答對應的磁盤文件名*/char*filename;/**真正的文件名,如果不匹配我們填入r->filename*/char*canonical_filename;/**此請求中抽取的PATH_INFO*/char*path_info;/**此請求中抽取的QUERY_ARGS*/char*args;/**st_mode,如果沒有此文件,該值設為0*/apr_finfo_tfinfo;/**包含URI組件的結構體*/apr_uri_tparsed_uri;/***處理函數(shù)接收或者拒絕當前請求的path_info的標志。所有的模塊應當尊重AP_REQ_ACCEPT_PATH_INFO和AP_REQ_REJECT_PATH_INFO的值,AP_REQ_DEFAULT_PATH_INFO表示遵從慣例。*這是對修訂中在HOOK_VERY_FIRST上根據(jù)用戶的喜好設定的。*/intused_path_info;/*一些其他的配置信息可能根據(jù).htaccess文件進行變化。*這些是配置向量,每一個模塊都有一個void*指針。*//**配置文件中的可選設置*/structap_conf_vector_t*per_dir_config;/**對“這個”請求的記錄*/structap_conf_vector_t*request_config;/***被這個請求訪問的.htaccess配置指令的鏈表。*注意,當心總是加到這個鏈表的頭部,而從不加到鏈表的尾部*這樣的話,一個子請求的鏈表可以臨時的指向父請求的鏈表。*/conststructhtaccess_result*htaccess;/**應用到此請求的輸出過濾鏈表*/structap_filter_t*output_filters;/**應用到此請求的輸入過濾鏈表*/structap_filter_t*input_filters;/**應用到此請求的協(xié)議層輸出過濾鏈表*/structap_filter_t*proto_output_filters;/**應用到此請求的協(xié)議層輸入過濾鏈表*/structap_filter_t*proto_input_filters;/**確定eosbucket已經(jīng)被發(fā)送出去的標志*/inteos_sent;/*在記錄最后面放置的事物是為了避免破壞二進制兼容性。*如果能夠記住對記錄重新排序以改善64位對齊,那再好不過了。*下次基于某種原因我們可能會破壞這種二進制兼容性。*/};server_recserver_rec對象定義了邏輯Web服務器。如果使用虛擬主機,那么每一個虛擬主機擁有自己的server_rec文件,使得該虛擬主機獨立于其他的虛擬主機。server_rec對象在服務器啟動階段時被創(chuàng)建并一直持續(xù)到整個httpd關閉為止。server_rec對象沒有自己的池,而服務器資源需要從進程池中分配,進程池被所有的服務器所共享。server_rec對象具有一個配置向量以及服務器資源,包括服務器名稱、服務器定義、資源和限制、日志信息等。server_rec對象對于程序員來說是僅次于request_rec的、第二重要的結構,它將在我們整個模塊編程討論中起著關鍵的作用。下面是摘自于httpd.h文件中的server_rec對象的完整定義。/**為每一個虛擬服務器存儲信息的結構體*/structserver_rec{/**本服務器所運行的進程*/process_rec*process;/**鏈表中的下一個服務器*/server_rec*next;/**服務器的名稱*/constchar*defn_name;/**服務器在配置文件中定義的行數(shù)*/unsigneddefn_line_number;/**/**ServerAlias服務器的通配符命名*//**/**ServerAlias服務器的通配符命名*//**包含指向模塊的每服務器配置結構指針的配置向量*/structap_conf_vector_t*module_config;/**包含指向模塊的每服務器配置結構指針的配置向量*/structap_conf_vector_t*module_config;/*契約信息*//**管理員的契約信息*/char*server_admin;/**服務器的主機名*/char*server_hostname;/**為重定向等*/apr_port_tport;/*日志文件——目前在模塊之間傳送日志*//**錯誤日志的名稱*/char*error_fname;/**錯誤日志文件的文件描述符*/apr_file_t*error_log;/**本服務器的日志級別*/intloglevel;/*服務器的模塊配置和默認項*//**如果本服務器是虛擬主機則為真*/intis_virtual;/**MIME類型信息等等,在我們開始檢查目錄信息之前取消*/structap_conf_vector_t*lookup_defaults;/*事務處理*//**服務器地址*/server_addr_rec*addrs;/**暫停時間,在我們放棄之前,Arp的間隔時間*/apr_interval_time_ttimeout;/**我們等待另外一個請求的Arp的間隔時間*/apr_interval_time_tkeep_alive_timeout;/**每個連接的最大請求數(shù)*/intkeep_alive_max;/**使用持續(xù)連接*/intkeep_alive;/**ServerPath的路徑名稱*/constchar*path;/**路徑的長度*/intpathlen;/**ServerAlias服務器的普通命名*/apr_array_header_t*names;/**此連接進入的服務器*//**此連接進入的服務器*/apr_array_header_t*wild_names;/**HTTP請求行的限制大小*/intlimit_req_line;/**任何請求頭部字段的限制大小*/intlimit_req_fieldsize;/**請求頭部字段的限制大小*/intlimit_req_fields;};conn_recconn_rec對象是一個TCP連接在Apache的內部表示。在Apache接收一個來自于客戶端的連接請求時conn_rec對象被創(chuàng)建,隨后在該連接結束時conn_rec對象被銷毀。通常由于一個連接被用來處理一個或者多個HTTP請求,因此一個conn_rec對象也對應著一個或者多個request_rec對象。絕大部分應用程序只關心請求,因此會忽略掉conn_rec對象,不過協(xié)議模塊和連接層過濾器需要使用conn_rec對象,有些模塊有時也會因為任務需要而使用conn_rec對象,如對一個HTTPKeepalive(持續(xù)連接)的生命周期內優(yōu)化資源。conn_rec沒有配置信息,但是它具有一個和連接相關的瞬時數(shù)據(jù)配置向量,以及一個連接資源池。conn_rec還擁有連接輸入和輸出過濾鏈,以及TCP連接的描述數(shù)據(jù)。區(qū)分請求和連接是非常重要的。請求總是連接的一個組成部分。Apache使用獨立的對象清晰地表示了請求和連接,除了一個重要的特殊情況。這個特殊情況我們將在第8章討論連接過濾的時候進行處理。下面是摘自于httpd.h文件中對conn_rec對象的完整定義。/**存儲每個連接的相關信息的結構*/structconn_rec{/**和此連接相關的池*/apr_pool_t*pool;server_rec*base_server;/**被http_vhost.c使用*/void*vhost_lookup_data;/*關于連接本身的信息*//**本地地址*/apr_sockaddr_t*local_addr;/**遠端地址*/apr_sockaddr_t*remote_addr;/**客戶端的IP地址*/char*remote_ip;/**如果可以獲取,則為客戶端的DNS名稱;如果沒有檢查則為NULL;如果沒有發(fā)現(xiàn),就為“”。該字段只是為get_remote_host()使用。*/char*remote_host;/**如果做rfc1413的查找則設定。該字段只是為get_remote_host()使用。*/char*remote_logname;/**我們還在談話么?*/unsignedaborted:1;/**/***this*連接的筆記:從一個連接發(fā)送筆記到另一個連接。/**/***this*連接的筆記:從一個連接發(fā)送筆記到另一個連接。/**我們將要為另一個請求保持此連接的激活?*@seeap_conn_keepalive_e*/ap_conn_keepalive_ekeepalive;/**我們做過double-reverseDNS?-1為是/失敗,0為沒有。*1為是/成功。*/signedintdouble_reverse:2;/**我們使用它多少次?*/intkeepalives;/**服務器的IP地址*/char*local_ip;/**當UseCanonicalName設定為DNS時,為ap_get_server_name使用。*(忽略HostnameLookups的設定)*/char*local_host;/**連接的ID,每個連接都不同*/longid;/**包含連接的每服務器配置結構的指針的配置向量*/structap_conf_vector_t*conn_config;*必須在本連接的所有請求上保持正確。*/apr_table_t*notes;/**本連接所使用的輸入過濾鏈表*/structap_filter_t*input_filters;/**本連接所使用的輸出過濾鏈表*/structap_filter_t*output_filters;/**本連接得分板信息的處理函數(shù)*/void*sbh;/**為所有bucket/brigade創(chuàng)建所使用的bucket分配器*/structapr_bucket_alloc_t*bucket_alloc;/**本連接的當前狀態(tài)*/conn_state_t*cs;/**輸入過濾器還有懸而未決的數(shù)據(jù)么?*/intdata_in_input_filters;};process_rec和我們以上討論的其他內核對象不同,process_rec是一個操作系統(tǒng)對象,而不是一個Web架構對象。當進程池提供所有的server_rec對象(并且通過s-〉process-〉pool來訪問server_rec對象),并且應用程序使用服務器生命周期內的資源時,應用程序需要關注server_rec對象和它們自身,其他情況下都不要關注server_rec對象。server_rec對象在httpd.h中定義,此處并沒有給出它的定義。2.5其他的關鍵API組件httpd.h頭文件定義了以上這些內核結構,不過它也只是應用開發(fā)者需要使用的很多API頭文件中的一個。這些頭文件屬于幾個松散邊界的種類,可以通過命名慣例標識出來:ap_頭文件一般定義了較低層次的API元素,通常(盡管不是總是)被其他頭文件包含而被間接訪問。http_頭文件定義了應用開發(fā)者比較感興趣的絕大部分關鍵的API。這些API也可以通過一些模塊暴露給腳本語言,例如mod_p

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論