工控網(wǎng)中基于Linux的嵌入式HTTP服務(wù)器設(shè)計(jì)
關(guān)鍵詞:嵌入式HTTP服務(wù)器 Linux 控制網(wǎng)絡(luò)
引言
控制網(wǎng)絡(luò)一般指以控制“事物對(duì)象”為特征的計(jì)算機(jī)網(wǎng)絡(luò)系統(tǒng),簡(jiǎn)稱Infranet(infrastructure network),它處在企業(yè)網(wǎng)(Intranet)的底層,構(gòu)成了整個(gè)企業(yè)網(wǎng)的基礎(chǔ)。近些年來(lái),在控制網(wǎng)絡(luò)中采用了現(xiàn)場(chǎng)總線(Field Bus)和工業(yè)以太網(wǎng)(Ethernet)兩種技術(shù)。出現(xiàn)這種情況主要有兩個(gè)原因:第一,目前存在多種現(xiàn)場(chǎng)總線標(biāo)準(zhǔn),不同的標(biāo)準(zhǔn)采用完全不同的通信協(xié)議,也就是說(shuō)現(xiàn)場(chǎng)總線的開(kāi)放性不夠;第二,以太網(wǎng)雖然能夠解決開(kāi)放性的問(wèn)題,并具備成本低廉、技術(shù)成熟等優(yōu)點(diǎn),但由于以太網(wǎng)最初是被設(shè)計(jì)用于以資源共享為目的的計(jì)算機(jī)局域網(wǎng),因此在實(shí)時(shí)性和可靠性上暫時(shí)還不能完全滿足工業(yè)控制的要求。事實(shí)上,目前一個(gè)較大規(guī)模的控制網(wǎng)絡(luò)往往綜合采用了這兩種技術(shù)。在現(xiàn)場(chǎng)層,由于強(qiáng)調(diào)實(shí)時(shí)性、可靠性和安全性,常采用現(xiàn)場(chǎng)總線技術(shù);在監(jiān)控管理層,考慮到采用不同標(biāo)準(zhǔn)的控制網(wǎng)段之間的集成以及與高層企業(yè)信息網(wǎng)絡(luò)的集成,一般采用以太網(wǎng)技術(shù)?,F(xiàn)場(chǎng)層的現(xiàn)場(chǎng)總線控制系統(tǒng)FCS(Field Control System)或其它設(shè)備級(jí)輕質(zhì)網(wǎng)絡(luò)通過(guò)網(wǎng)關(guān)或嵌入式HTTP服務(wù)器與高層以太網(wǎng)相連。這樣,不僅采用不同協(xié)議的控制網(wǎng)段能夠?qū)崿F(xiàn)互聯(lián),而且各個(gè)控制網(wǎng)段能方便地與高層企業(yè)信息網(wǎng)互通,從而最終實(shí)現(xiàn)企業(yè)網(wǎng)的管控一體化和對(duì)現(xiàn)場(chǎng)設(shè)備的Internet遠(yuǎn)程監(jiān)控。通過(guò)以上分析可以看出,控制網(wǎng)絡(luò)中的網(wǎng)關(guān)或嵌入式HTTP服務(wù)器起著連接現(xiàn)場(chǎng)層和監(jiān)迭管理層的作用,因此它是整個(gè)控制網(wǎng)絡(luò)的關(guān)鍵設(shè)備。
網(wǎng)關(guān)或嵌入式HTTP服務(wù)器與傳統(tǒng)的嵌入式系統(tǒng)相比,有一些不同的特性。傳統(tǒng)的嵌入式系統(tǒng)是面向應(yīng)用、有一些不同的特性。傳統(tǒng)的嵌入式系統(tǒng)是面向應(yīng)用、面向產(chǎn)品的,強(qiáng)調(diào)成本和高效設(shè)計(jì)系統(tǒng),因此本質(zhì)上不具備通用性和可移植性。網(wǎng)關(guān)或嵌入式HTTP服務(wù)器由于處在現(xiàn)場(chǎng)層和監(jiān)控管理層的中間,因此它與具體應(yīng)用和產(chǎn)品是一種弱耦合的關(guān)系。同時(shí),技術(shù)發(fā)展的趨勢(shì)是:硬件成本越來(lái)越低,功能越來(lái)越強(qiáng),越來(lái)越多的芯片和板卡具備“平臺(tái)”的特點(diǎn),適用于多種應(yīng)用場(chǎng)合。嵌入式實(shí)時(shí)操作系統(tǒng)(Embedded Real Time Operationg System)的發(fā)展更是為嵌入式軟件提供了一個(gè)通用的軟件平臺(tái)。綜上所述,在網(wǎng)關(guān)或嵌入式HTTP服務(wù)器設(shè)計(jì)中,考慮通過(guò)選用適合的硬件和嵌入式實(shí)時(shí)操作系統(tǒng),使整個(gè)系統(tǒng)具備相當(dāng)?shù)耐ㄓ眯院涂梢浦残?。?duì)于連接不同的設(shè)備級(jí)輕質(zhì)網(wǎng)絡(luò)或不同的應(yīng)用,只需要通過(guò)更換硬件模塊和對(duì)代碼作最小的修改即可實(shí)現(xiàn)。
1 基于Linux的嵌入式HTTP服務(wù)器的結(jié)構(gòu)
為了實(shí)現(xiàn)設(shè)計(jì)目標(biāo),嵌入式HTTP服務(wù)器一般應(yīng)采用功能較強(qiáng)的能用PC、工業(yè)PC、或高檔MPU作為硬件平臺(tái),嵌入式實(shí)時(shí)操作系統(tǒng)作為軟件平臺(tái)進(jìn)行平發(fā)。硬件平臺(tái)應(yīng)具備以太網(wǎng)口和一個(gè)或多個(gè)通信模塊,比如RS232、RS485、CAN通信卡等。嵌入式實(shí)時(shí)操作系統(tǒng)實(shí)現(xiàn)了TCP/IP等網(wǎng)絡(luò)協(xié)議,并提供實(shí)時(shí)任務(wù)、進(jìn)程管理、內(nèi)存管理、文件系統(tǒng)、API等功能。
Linux操作系統(tǒng)是一種多進(jìn)程,多用戶的通用操作。由于它具備免費(fèi)、源碼公開(kāi)、內(nèi)核可裁減、支持多線程、網(wǎng)絡(luò)功能強(qiáng)大、設(shè)計(jì)精巧、性能穩(wěn)定的特點(diǎn),因此近年它也被廣泛用到嵌入式系統(tǒng)的設(shè)計(jì)中。一個(gè)應(yīng)用于嵌入式系統(tǒng)的Linux經(jīng)過(guò)裁減和重新編譯后只包括進(jìn)程管理、內(nèi)存管理、文件系統(tǒng)、若干個(gè)驅(qū)動(dòng)程序和實(shí)用的函數(shù)等。
下面以本人參與的轉(zhuǎn)子秤控制系統(tǒng)為例來(lái)說(shuō)明一個(gè)基于Linux的嵌入式HTTP服務(wù)器的結(jié)構(gòu)。轉(zhuǎn)子秤是水泥工業(yè)中的關(guān)鍵計(jì)量喂料設(shè)備,一條大型的生產(chǎn)線需要許多臺(tái)轉(zhuǎn)子秤,對(duì)轉(zhuǎn)子秤的控制涉及到重量、轉(zhuǎn)速、溫度、一氧化碳含量等若干個(gè)參量。由于現(xiàn)場(chǎng)環(huán)境的高噪聲、高粉塵、高電磁干擾,無(wú)法在現(xiàn)場(chǎng)配備鍵盤、顯示器、觸摸屏等人機(jī)交互設(shè)備,無(wú)法在現(xiàn)場(chǎng)實(shí)現(xiàn)對(duì)設(shè)備的監(jiān)控和維護(hù)。同時(shí),一條生產(chǎn)線有多臺(tái)轉(zhuǎn)子秤,為每臺(tái)轉(zhuǎn)子秤配備人機(jī)交互設(shè)備也是不經(jīng)濟(jì)的。為此,考慮為整個(gè)系統(tǒng)設(shè)計(jì)一個(gè)嵌入式HTTP服務(wù)器,各轉(zhuǎn)子秤控制器與嵌入式HTTP服務(wù)器用CAN總線相連。通過(guò)嵌入式HTTP服務(wù)器實(shí)現(xiàn)對(duì)整個(gè)系統(tǒng)的在線監(jiān)控和遠(yuǎn)程監(jiān)控。在嵌入式HTTP服務(wù)器的設(shè)計(jì)中,選用研祥公司PC104總線的486X嵌入式CPU卡作為硬件平臺(tái),該板卡是具有128MB的在板ROM、CF卡接口和以太網(wǎng)接口等。選擇該板卡的原因是PC104總線的功能擴(kuò)展模塊非常豐富,通過(guò)選擇不同的模塊很容易就支持多種總線。軟件平臺(tái)方面,選用Linux2.0內(nèi)核并對(duì)它作適當(dāng)裁減。整個(gè)嵌入式HTTP服務(wù)器的結(jié)構(gòu)簡(jiǎn)圖如圖1所示。
2 基于Linux的嵌入式HTTP服務(wù)器的設(shè)計(jì)
工控領(lǐng)域的嵌入式HTTP服務(wù)器應(yīng)該具備如下基本功能。
①實(shí)時(shí)數(shù)據(jù)發(fā)布。實(shí)時(shí)數(shù)據(jù)主要包括系統(tǒng)運(yùn)行過(guò)程中設(shè)備的各種狀態(tài)信息。嵌入式HTTP服務(wù)器將實(shí)時(shí)數(shù)據(jù)以網(wǎng)頁(yè)形式發(fā)布到Internet上,且動(dòng)態(tài)實(shí)時(shí)刷新??蛻艨梢酝ㄟ^(guò)瀏覽器訪問(wèn)這些實(shí)時(shí)信息。
②參數(shù)設(shè)置。參數(shù)包括運(yùn)行參數(shù)和設(shè)備狀態(tài)參數(shù),如各種初始值、常數(shù)等。嵌入式HTTP服務(wù)器接收到客戶提交的參數(shù)設(shè)備請(qǐng)求后,執(zhí)行參數(shù)寫入操作。
③遠(yuǎn)程實(shí)時(shí)控制。遠(yuǎn)程實(shí)時(shí)控制允許遠(yuǎn)程用戶在線地控制系統(tǒng)中的相應(yīng)執(zhí)行機(jī)構(gòu),比如電機(jī)、電磁閥等。嵌入式HTTP服務(wù)器接收到遠(yuǎn)方客戶提交的控制操作請(qǐng)求后,將下發(fā)控制命令驅(qū)動(dòng)監(jiān)控系統(tǒng)中相應(yīng)的執(zhí)行機(jī)構(gòu)。
④訪問(wèn)級(jí)別設(shè)置和權(quán)限認(rèn)證。只有權(quán)限不低于要求訪問(wèn)級(jí)別的客戶,經(jīng)嵌入式HTTP服務(wù)器認(rèn)證后,方可進(jìn)行其權(quán)限范圍內(nèi)的監(jiān)控操作。
3 主要實(shí)現(xiàn)技術(shù)
3.1 超文本傳輸協(xié)議
HTTP協(xié)議是一個(gè)面向事務(wù)、無(wú)狀態(tài)的應(yīng)用層協(xié)議。在傳輸層,HTTP協(xié)議使用請(qǐng)求(request)/響應(yīng)(response)模型。一次簡(jiǎn)單的HTTP事務(wù)包括以下過(guò)程。首先,客戶(瀏覽器)發(fā)起和建立一條到服務(wù)器的TCP連接。然后,客戶發(fā)送一個(gè)HTTP請(qǐng)求到服務(wù)器,請(qǐng)求包含方法、URI、協(xié)議版本和一個(gè)類MIME報(bào)文。服務(wù)器解析HTTP請(qǐng)求后,給出相應(yīng)的HTTP響應(yīng),響應(yīng)包括協(xié)議版本、狀態(tài)碼、解釋狀態(tài)碼的簡(jiǎn)短短語(yǔ)和一個(gè)類MIME報(bào)文。最后,釋放TCP連接。Linux操作系統(tǒng)為用戶提供了稱為BSD Socket的網(wǎng)絡(luò)編程接口。利用其中的TCP套接口函數(shù),可以非常方便地實(shí)現(xiàn)HTTP協(xié)議。
HTTP1.0為每一次HTTP請(qǐng)求/響應(yīng)建立一條新的TCP連接,由于建立一條TCP連接要經(jīng)歷3次握手,因此效率不高。HTTP1.1提出了可持續(xù)性連接的概念。HTTP1.1只建立一次TCP連接,而重復(fù)地使用它傳送一條素的請(qǐng)求/響應(yīng)消息,減少了額外開(kāi)銷。在嵌入式HTTP服務(wù)器中,一般使用HTTP1.1協(xié)議。HTTP1.1協(xié)議的細(xì)節(jié)請(qǐng)參考RFC2616。
3.2 通用網(wǎng)關(guān)接口CGI
參數(shù)設(shè)置和遠(yuǎn)程控制功能都是通過(guò)CGI(通用網(wǎng)關(guān)接口)程序和表單實(shí)現(xiàn)的。CGI使用HTML表單向Web服務(wù)器發(fā)送信息?;菊Z(yǔ)法如下:
FORM METHOD=get/post ACTION=URL>/FORM>
其中,METHOD屬性指定將數(shù)據(jù)傳送到Web服務(wù)器的方法。輸入方法有兩種:GET和POST。ACTION屬性定義要對(duì)表單數(shù)據(jù)進(jìn)行處理的CGI腳本的URL。
CGI的工作流程是首先由瀏覽器將用戶輸入的數(shù)據(jù)傳遞給Web服務(wù)器,Web服務(wù)器根據(jù)接收到的數(shù)據(jù)設(shè)置環(huán)境變量并啟動(dòng)CGI腳本,CGI腳本從環(huán)境變量中讀取所需要的數(shù)據(jù)并進(jìn)行相應(yīng)處理,最后使用STDOUT輸出HTML形式的結(jié)果文件,經(jīng)Web服務(wù)器送回瀏覽器,最終顯示給用戶。傳統(tǒng)的CGI程序與服務(wù)器代碼分開(kāi),是一個(gè)符號(hào)CGI標(biāo)準(zhǔn)的可執(zhí)行文件,并儲(chǔ)存在CF卡等存儲(chǔ)設(shè)備上,一般用腳本語(yǔ)言編寫??紤]到嵌入式HTTP服務(wù)器要求速度快,功能和代碼都盡可能精簡(jiǎn)的特點(diǎn),可以把原先由可執(zhí)行文件完成的功能用C函數(shù)實(shí)現(xiàn),放在服務(wù)器代碼內(nèi)部,并直接從HTTP請(qǐng)求報(bào)文接收數(shù)據(jù)。與傳統(tǒng)CGI程序相比,這種方法具備如下特點(diǎn):
*不需要標(biāo)準(zhǔn)輸入,CGI函數(shù)可以直接獲取到瀏覽器送來(lái)的信息;
*不需要標(biāo)準(zhǔn)輸出,CGI函數(shù)可以直接將數(shù)據(jù)送回給瀏覽器;
*不需要環(huán)境變量,CGI和Web服務(wù)器在同一程序中實(shí)現(xiàn),不需要環(huán)境變量來(lái)交換信息。
3.3 自定義標(biāo)記
要在網(wǎng)頁(yè)中顯示工控系統(tǒng)中大量的實(shí)時(shí)數(shù)據(jù),常規(guī)方法是將HTML代碼直接集成到程序代碼中,或者反之將C程序代碼集成到HTML標(biāo)記語(yǔ)言中。這兩種方法均要求開(kāi)發(fā)人員對(duì)HTML標(biāo)記語(yǔ)言的語(yǔ)法細(xì)節(jié)非常熟悉。網(wǎng)頁(yè)或程序結(jié)構(gòu)的單方面調(diào)整都將導(dǎo)致整個(gè)系統(tǒng)全盤修改,系統(tǒng)不具備靈活性與可擴(kuò)展性。HTML的精髓在于該語(yǔ)言的“標(biāo)記”性,各種不同標(biāo)記的具體含義是由服務(wù)器和瀏覽器進(jìn)行解析。因此,當(dāng)現(xiàn)有標(biāo)記不能滿足新的應(yīng)用需求時(shí),可以自行定義新的標(biāo)記,只需服務(wù)器將自定義標(biāo)記解析為標(biāo)準(zhǔn)標(biāo)記,然后傳送給瀏覽器即可。在本項(xiàng)目中,主要的實(shí)時(shí)數(shù)據(jù)轉(zhuǎn)速、重量、一氧化碳含量等狀態(tài)信息,可以定義相應(yīng)的標(biāo)記。服務(wù)器中解析相應(yīng)標(biāo)記的函數(shù)同樣用C語(yǔ)言來(lái)實(shí)現(xiàn)。運(yùn)行時(shí),當(dāng)客戶端發(fā)出查看某實(shí)時(shí)網(wǎng)頁(yè)的請(qǐng)求后,嵌入式HTTP服務(wù)器將相應(yīng)的網(wǎng)頁(yè)文件從電子盤加載到內(nèi)存進(jìn)行逐項(xiàng)解析。當(dāng)辨識(shí)出自定義標(biāo)記后,就調(diào)用相應(yīng)的函數(shù)。該函數(shù)返回該標(biāo)記對(duì)應(yīng)的當(dāng)前值,并置換HTML文件流中的自定義標(biāo)記。最后,嵌入式HTTP服務(wù)器將解析結(jié)果發(fā)送給客戶端。實(shí)時(shí)網(wǎng)頁(yè)的設(shè)計(jì)與相應(yīng)的HTTP服務(wù)器處理程序得以分離,處于一種弱耦合關(guān)聯(lián)狀態(tài)。這樣,網(wǎng)頁(yè)界面的調(diào)整不會(huì)影響HTTP服務(wù)器的程序設(shè)計(jì),HTTP服務(wù)器程序的修改也與網(wǎng)頁(yè)界面設(shè)計(jì)無(wú)關(guān),整個(gè)嵌入式HTTP服務(wù)器具備靈活性和可擴(kuò)展性。
3.4 多線程
最初的進(jìn)程定義包含程序、資源及其執(zhí)行三部分,其中程序通常指代碼,資源通常包括 內(nèi)存資源、I/O資源、信號(hào)處理等,而程序的執(zhí)行指執(zhí)行上下文,這一部分后來(lái)發(fā)展為線程。在線程的概念出現(xiàn)以前,為了減小進(jìn)程切換的開(kāi)銷,操作系統(tǒng)設(shè)計(jì)者逐漸修改正進(jìn)程的概念,允許將進(jìn)程所占有的資源從其主體剝離出來(lái),允許某些進(jìn)程共離享一部分資源,例如文件、信號(hào)、數(shù)據(jù)內(nèi)存、甚至代碼,這就是輕質(zhì)進(jìn)程的概念。Linux內(nèi)核的2.0.x版本就已經(jīng)實(shí)現(xiàn)了輕質(zhì)進(jìn)程。應(yīng)用程序可以通過(guò)一個(gè)統(tǒng)一的clone()系統(tǒng)調(diào)用接口,用不同的參數(shù)指定創(chuàng)建輕質(zhì)進(jìn)程還是普通進(jìn)程。在內(nèi)核中,clone()調(diào)用經(jīng)過(guò)參數(shù)傳遞和解釋后會(huì)調(diào)用do_fork(),這個(gè)核內(nèi)函數(shù)同時(shí)也是fork、vfork()系統(tǒng)調(diào)用的最終實(shí)現(xiàn)。在do_fork()中,不同的flone_flags將導(dǎo)致不同的行為。在LinuxThreads中,使用(CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND)參數(shù)調(diào)用clone()創(chuàng)建“線程”,表示共享內(nèi)存、共享文件系統(tǒng)、共享文件描述符表,以及共享信號(hào)處理方式。Linux操作系統(tǒng)下,已經(jīng)實(shí)現(xiàn)基于輕質(zhì)進(jìn)程的符號(hào)POSIX1003.C標(biāo)準(zhǔn)的線程庫(kù)LinuxThreads。
在傳統(tǒng)的Unix服務(wù)器程序設(shè)計(jì)中,為了使服務(wù)器具備并發(fā)處理連接的能力,通常采用父進(jìn)程處理連接,并調(diào)用fork()創(chuàng)建子進(jìn)程來(lái)處理用戶請(qǐng)求的方法。這種方法的缺點(diǎn)是進(jìn)程創(chuàng)建慢,耗費(fèi)資源,進(jìn)程切換開(kāi)銷大,進(jìn)程之間通信比較困難等,不適用對(duì)資源、速度有要求的嵌入式系統(tǒng)。因此,在嵌入式HTTP服務(wù)器的開(kāi)發(fā)中使用線程的方法。利用LinuxThreads提供的pthread_create()等函數(shù)派生出線程,也即輕質(zhì)進(jìn)程來(lái)處理多個(gè)HTTP請(qǐng)求。
4 工作流程和代碼設(shè)計(jì)
4.1工作流程
嵌入式HTTP服務(wù)器程序開(kāi)始運(yùn)行時(shí),主進(jìn)程首先創(chuàng)建一個(gè)接口,并和主機(jī)地址綁定到一起,隨后置為被動(dòng)監(jiān)聽(tīng)狀態(tài),等待客戶端連接請(qǐng)求的到來(lái)。分別用函數(shù)socket()創(chuàng)建一個(gè)接口,bind()綁定地址,listen()監(jiān)聽(tīng),accept()接收來(lái)完成。當(dāng)建立一個(gè)TCP連接后,函數(shù)accept()返回一個(gè)新的套接口描述符,主進(jìn)程就創(chuàng)建一個(gè)新的子線程(輕質(zhì)進(jìn)程)處理這個(gè)新的連接。
子線程用于處理每具體的HTTP請(qǐng)求。子線程首先解析用戶的HTTP請(qǐng)求。當(dāng)用戶請(qǐng)求一個(gè)網(wǎng)頁(yè)時(shí),子線程查找文件系統(tǒng)。如果該網(wǎng)頁(yè)文件存在,且通過(guò)權(quán)限認(rèn)證,就把它從CF卡讀入內(nèi)存并掃描,發(fā)現(xiàn)有自定義標(biāo)記則調(diào)用相應(yīng)函數(shù)進(jìn)行處理,最后把結(jié)果返回給瀏覽器;否則給一個(gè)簡(jiǎn)單的出錯(cuò)消息。當(dāng)用戶是上傳數(shù)據(jù)時(shí),子線程調(diào)用相應(yīng)函數(shù)讀取數(shù)據(jù)進(jìn)行處理,并返回處理結(jié)果給瀏覽器。
4.2 代碼設(shè)計(jì)
在嵌入式HTTP服務(wù)器的代碼設(shè)計(jì)中,考慮到代碼的移植性和擴(kuò)展性,利用C語(yǔ)言實(shí)現(xiàn)了面向?qū)ο箫L(fēng)格的代碼結(jié)構(gòu)。代碼主要由兩上數(shù)據(jù)結(jié)構(gòu)request_inf和response_inf以及其上一組操作函數(shù)組成。
結(jié)構(gòu)request_inf和response_inf分別用來(lái)保存HTTP請(qǐng)求報(bào)文和響應(yīng)報(bào)文的所有信息。在結(jié)構(gòu)定義時(shí),應(yīng)根據(jù)具體應(yīng)用特點(diǎn)設(shè)計(jì)結(jié)構(gòu)包含的成分。
嵌入式HTTP服務(wù)器的函數(shù)包括通用函數(shù)、CGI函數(shù)和自定義標(biāo)記處理函數(shù)等,其中通用函數(shù)是一些與HTTP1.1協(xié)議有關(guān)的函數(shù)。
(1)通用函數(shù)
*void prase_request_line(char *,struct *request_inf)
該函數(shù)用來(lái)解析HTTP請(qǐng)求報(bào)文的請(qǐng)求行(Request_Line),并把相應(yīng)信息存放在結(jié)構(gòu)request_inf中。其中,對(duì)請(qǐng)求行中URI部分的解析包括兩種情況。如果用戶請(qǐng)求一個(gè)網(wǎng)頁(yè),則獲取文件路徑、文件類型;如果用戶要求上傳數(shù)據(jù),則把數(shù)據(jù)放在一個(gè)字符數(shù)組中。然后將文件路徑和類型,或者指向該數(shù)組的指針、方法、版本號(hào)信息都放入結(jié)構(gòu)request_inf中。
*void prease_general_header(char*,struct*request_inf)
該函數(shù)用來(lái)解析HTTP請(qǐng)求報(bào)文的調(diào)用首部(General_Header)。之所以把此函數(shù)與函數(shù)prase_request_line()分開(kāi),是考慮到程序的修植性和擴(kuò)展性。請(qǐng)求行和通用首部是請(qǐng)求報(bào)文中的不同部分,不不同的場(chǎng)合下,要求解析的信息可能存在差導(dǎo)師。同時(shí),這樣也能使程序結(jié)構(gòu)更清楚。比如,本項(xiàng)目要從通用首部解析字段Keep_Alive。該字段指明一個(gè)最長(zhǎng)的時(shí)間或最大請(qǐng)求數(shù)目,在此范圍內(nèi)可以保持TCP連接不被釋放(即前文提到的HTTP1.1的持續(xù)連接特性,persistent connection)。
*void prase_request_header(char*,struct*request_inf)
void prase_entity_header(char*,struct*request_inf)
HTTP請(qǐng)求報(bào)文的請(qǐng)求頭部用來(lái)說(shuō)明瀏覽器的一些信息,實(shí)體頭部則用來(lái)說(shuō)明請(qǐng)求報(bào)文中可能存在的實(shí)體主體信息。本項(xiàng)目實(shí)際上并不需要使用這兩個(gè)函數(shù)來(lái)獲取相關(guān)信息,但考慮到程序的擴(kuò)展性和移植性,此處仍然把它列出來(lái),它們是兩個(gè)空函數(shù)。
*send_status_line(int fd,struct *response_inf)
此函數(shù)用來(lái)產(chǎn)生一個(gè)HTTP響應(yīng)報(bào)文的狀態(tài)行(Status_line)。狀態(tài)行包括三部分內(nèi)容,即HTTP版本、狀態(tài)碼以及解釋狀態(tài)碼的簡(jiǎn)單短語(yǔ)。這些信息預(yù)先放在結(jié)構(gòu)response_inf中。
*send_general_header(int fd,struct*response_inf)
send_response_header(int fd,struct*response_inf)
send_entity_header(int fd,struct*response_inf)
這三個(gè)函數(shù)分別用來(lái)產(chǎn)生HTTP響應(yīng)報(bào)文的通用首部、響應(yīng)首部(Response_header)和實(shí)體首部。嵌入式HTTP服務(wù)器是一個(gè)瘦服務(wù)器,功能非常簡(jiǎn)單。因此HTTP響應(yīng)報(bào)文的通用首部、響應(yīng)首部和實(shí)體首部中的可選字段許多是不需要的,還有許多是固定不變的,例如Last_modified和Content_type字段。Last_modified字段指出資源上次被修改的時(shí)間并由接收方解釋。如果接收方已有此資源的拷貝,但此拷貝比Last-Modified域所指定的要舊,那該拷貝就是過(guò)期的。由于網(wǎng)頁(yè)文件中含有自定義標(biāo)記,具有實(shí)時(shí)性,所以此字段根本沒(méi)有含有Content_type字段指出實(shí)體的媒體類型,本項(xiàng)目中的嵌入式HTTP服務(wù)器被設(shè)計(jì)成只支持HTML類型,因此該字段的內(nèi)容總是Content_type=text/html。有關(guān)服務(wù)器和資源的所有標(biāo)題域信息都被放入結(jié)構(gòu)response_inf中。
*send_white_line(int fd)
此函數(shù)用于實(shí)體首部和實(shí)體之間傳送一個(gè)空白行。
*void send_entity_body(int fd,char *buff_file)
此函數(shù)用來(lái)傳遞實(shí)體主體,實(shí)體主體實(shí)際上是一個(gè)處理后的網(wǎng)頁(yè)文件,它被放在指針buff_file指向的緩沖區(qū)內(nèi)。
*void zero_request_inf(struct*request_inf)
void zero_response_inf(struct*response_inf)
這兩個(gè)函數(shù)用于結(jié)構(gòu)request_inf和response_inf清零。
*void get_file(struct*request_inf,struct * response_inf,char*buff_file,void*,void*)
該函數(shù)用來(lái)處理用戶HTTL請(qǐng)求。首先,函數(shù)會(huì)檢查request_inf結(jié)構(gòu),判斷用戶是請(qǐng)求一個(gè)網(wǎng)頁(yè)文件還是上傳數(shù)據(jù)。當(dāng)用戶請(qǐng)求網(wǎng)頁(yè)文件時(shí),函數(shù)將根據(jù)request_inf結(jié)構(gòu)中的文件路徑信息,在文件系統(tǒng)錄找此文件。如果文件不存在或不具備權(quán)限,則函數(shù)將狀態(tài)碼和解釋短語(yǔ)寫入結(jié)構(gòu)response_inf,然后直接返回;否則讀取文件并調(diào)用自定義標(biāo)記處理函數(shù),對(duì)標(biāo)記進(jìn)行處理,處理過(guò)的網(wǎng)頁(yè)文件被放入buff_file指向的緩沖區(qū)內(nèi),并把狀態(tài)碼、解釋短路和與實(shí)體有關(guān)的一些信息寫入結(jié)構(gòu)response_inf。當(dāng)用戶上傳數(shù)據(jù)時(shí),該函數(shù)調(diào)用CGI處理函數(shù)向CAN總線網(wǎng)絡(luò)發(fā)送幀,然后將狀態(tài)碼和解釋短路寫入結(jié)構(gòu)response_inf。利用狀態(tài)碼和解釋短語(yǔ)只能用“200,OK”或“500,Internal Server Error”等,簡(jiǎn)單反映執(zhí)行情況。用戶要獲取詳細(xì)信息,可待一段合適的時(shí)間后請(qǐng)求網(wǎng)頁(yè)文件。函數(shù)中兩個(gè)void指針?lè)謩e指向自定義標(biāo)記處理函數(shù)和CGI處理函數(shù),或者對(duì)應(yīng)的函數(shù)指針數(shù)組。
(2)自定義標(biāo)記處理函數(shù)和CGI處理函數(shù)
自定義標(biāo)記處理函數(shù)用于對(duì)自定義的處理,每一類自定義標(biāo)記對(duì)對(duì)應(yīng)一種自定義標(biāo)記處理函數(shù),同一類自定義標(biāo)記的不同數(shù)據(jù)點(diǎn)利用參數(shù)來(lái)區(qū)分,比如轉(zhuǎn)子秤1的重量標(biāo)記可以用weight1來(lái)表示。所有的自定義標(biāo)記處理函數(shù)被放在一起,構(gòu)成一個(gè)函數(shù)指針數(shù)組。自定義標(biāo)記處理函數(shù)向CAN總線網(wǎng)絡(luò)發(fā)送遠(yuǎn)程幀和接收數(shù)據(jù)幀,獲取相應(yīng)的狀態(tài)信息。CGI總線網(wǎng)絡(luò)發(fā)送遠(yuǎn)程幀和接收數(shù)據(jù)幀,獲取相應(yīng)的狀態(tài)信息。CGI處理函數(shù)用變量名來(lái)區(qū)分,同一類變量對(duì)應(yīng)一種CGI處理函數(shù)。與自定義標(biāo)記處理函數(shù)類似,所有的CGI處理函數(shù)也被放在一起,構(gòu)成一個(gè)函數(shù)指針數(shù)組。由于自定義標(biāo)記函數(shù)和CGI處理函數(shù)類型眾多,這里就不列舉了。
結(jié)語(yǔ)
我們?cè)O(shè)計(jì)的嵌入式HTTP服務(wù)器具備良好的通用性和可移植性。通過(guò)更換或增加PC104通信模塊,該服務(wù)器能夠支持不同的現(xiàn)場(chǎng)總線,或同時(shí)連接幾種不同的設(shè)備級(jí)輕質(zhì)網(wǎng)絡(luò)。同時(shí)在服務(wù)器代碼設(shè)計(jì)中,用C語(yǔ)言實(shí)現(xiàn)了面向?qū)ο箫L(fēng)格的代碼結(jié)構(gòu)。這樣,如果要求服務(wù)器端具備更多的特性,只需要簡(jiǎn)單修改結(jié)構(gòu)request_inf、response_inf、操作函數(shù)和網(wǎng)頁(yè)文件即可達(dá)到目的。這種設(shè)計(jì)思路不僅適用于嵌入式HTTP服務(wù)器,隨著硬件技術(shù)尤其是嵌入式操作系統(tǒng)技術(shù)的發(fā)展,它同樣能夠應(yīng)用到其它嵌入式產(chǎn)品的開(kāi)發(fā)中。
linux操作系統(tǒng)文章專題:linux操作系統(tǒng)詳解(linux不再難懂)
評(píng)論