大二的時(shí)候就開(kāi)始接觸CGI了,那時(shí)候用perl、php都寫(xiě)過(guò)CGI程序,對(duì)CGI的了解
也浮于表面上,最近由于工作需要,需要用C來(lái)寫(xiě)CGI程序,是時(shí)候弄清楚CGI內(nèi)部的工
作機(jī)制了。
1. CGI是什么?
相信很多人和我之前一樣,說(shuō)到CGI,會(huì)熟練的蹦出一句“Common Gateway
Interface ”,沒(méi)錯(cuò),這確實(shí)是CGI的全稱(chēng),可以翻譯為“通用網(wǎng)關(guān)接口”,可一說(shuō)到它的
用處,有多少人能夠講清楚? 沒(méi)關(guān)系,現(xiàn)在我就幫大家來(lái)解決這個(gè)困惑。按照CGI 1.1
里面的說(shuō)法“The Common Gateway Interface (CGI) is a simple interface for
running external programs, software or gateways under an information server in
a platform–idependent manner. Currently, the supported information servers
are HTTP servers.”,和我們熟悉的一樣,CGI現(xiàn)在都用在http服務(wù)器上,那么CGI能夠
提供怎樣的便利呢?答案如下:“A plain HTML document that the Web daemon
retrieves is static, which means it exists in a constant state: a text file
that doesn’t change. A CGI program, on the other hand, is executed in
real-time, so that it can output dynamic information.”
2. CGI接口定義
目前關(guān)于CGI接口最新的版本是1.1, 既然CGI程序充當(dāng)?shù)慕巧且粋€(gè)Gateway,那么
這個(gè)Gateway的兩端是什么?沒(méi)錯(cuò),是Http Server(Web Server)的輸入和輸出,換句話(huà)說(shuō)
,CGI程序從Web Server那里獲得瀏覽器發(fā)過(guò)來(lái)的數(shù)據(jù),進(jìn)行相應(yīng)處理后,輸出瀏覽器識(shí)別
的html文本給Web Server。為了便于理解, 還是用流程圖示意一下。
client Web Server CGI程序
http協(xié)議 CGI接口
發(fā)送請(qǐng)求---->接受請(qǐng)求并將數(shù)據(jù)處理發(fā)送給CGI程序--->獲得處理過(guò)的數(shù)據(jù)并解析
接受數(shù)據(jù)<----獲得CGI返回的數(shù)據(jù)并發(fā)送給客戶(hù)端<---處理數(shù)據(jù)并返回html數(shù)據(jù)
圖 1
本文討論的重點(diǎn)就是這個(gè)CGI接口, CGI程序通過(guò)環(huán)境變量和標(biāo)準(zhǔn)輸入獲得數(shù)據(jù),通過(guò)標(biāo)
準(zhǔn)輸出和標(biāo)準(zhǔn)錯(cuò)誤輸出發(fā)送數(shù)據(jù),那么這個(gè)到底是怎么實(shí)現(xiàn)的呢?
3. CGI接口實(shí)現(xiàn)
其實(shí)Web Server和CGI程序就是兩個(gè)進(jìn)程,要實(shí)現(xiàn)CGI接口就是如何實(shí)現(xiàn)這兩個(gè)進(jìn)程的通信
,Web Server獲得瀏覽器發(fā)送過(guò)來(lái)的請(qǐng)求后,將數(shù)據(jù)做相應(yīng)處理,然后fork一個(gè)子進(jìn)程處
理客戶(hù)請(qǐng)求,子進(jìn)程組織相應(yīng)的環(huán)境變量和參數(shù)準(zhǔn)備傳遞給CGI程序,然后調(diào)用execvp執(zhí)
行CGI程序。CGI程序有自己的環(huán)境變量,就是如上實(shí)現(xiàn)的,第二節(jié)說(shuō)過(guò),CGI程序除了通
過(guò)環(huán)境變量獲得數(shù)據(jù)外(其實(shí)這是get方法獲取數(shù)據(jù)的手段),還通過(guò)標(biāo)準(zhǔn)輸入獲得數(shù)據(jù)(pos
t方法獲取數(shù)據(jù)的方法),并且返回的數(shù)據(jù)是發(fā)送到標(biāo)準(zhǔn)輸出。相信你和我之前有一樣的疑
問(wèn),為什么CGI程序能夠從標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出讀寫(xiě)數(shù)據(jù)?其實(shí)這是通過(guò)管道和dup2系統(tǒng)
調(diào)用實(shí)現(xiàn)的,見(jiàn)下面的示意圖:
_____________________
dup2| |
(CGI program)read<-stdin<--|p[0]--管道1--p[1]|<-write (http server)
|_____________________|
圖2: CGI讀的實(shí)現(xiàn)
_____________________
dup2| |
(CGI program)write->stdout-->|p[1]--管道2--p[0]|->read (http server)
|_____________________|
圖3: CGI寫(xiě)的實(shí)現(xiàn)
4. 如何寫(xiě)CGI程序
有了上述的講述后,應(yīng)該算基本熟悉CGI的內(nèi)幕了,這樣寫(xiě)起CGI程序也會(huì)得心應(yīng)手,
首先獲得相應(yīng)的環(huán)境變量并保存,然后就是數(shù)據(jù)處理,根據(jù)REQUEST_METHOD環(huán)境變量判斷
表單提交的方法是GET還是METHOD,如何是GET,則從QUERY_STRING里面獲取數(shù)據(jù),如果是
POST, 那么從stdin讀取長(zhǎng)度CONTENT_LENGTH的數(shù)據(jù)。下面就是數(shù)據(jù)處理,組織html的輸
出頁(yè)面,并用printf輸出。
5. 小結(jié)
上面講的其實(shí)只是一個(gè)概況,關(guān)于CGI的接口有興趣的可以去看看這兩個(gè)網(wǎng)頁(yè):
http://cgi-spec.golux.com/draft-coar-cgi-v11-03-clean.html
http://hoohoo.ncsa.uiuc.edu/cgi/intro.html
我敘述的可能有些地方也有問(wèn)題,歡迎提出! 另外關(guān)于CGI實(shí)現(xiàn)的代碼可以看看
開(kāi)源軟件"thttpd",這是一個(gè)輕量級(jí)的http server,實(shí)現(xiàn)的很講究,主頁(yè)在
http://www.acme.com/software/thttpd/
完畢!