摘 要: 隨著計算機技術和網絡技術的快速發展,以嵌入式設備為主的監控系統、信息家電和通信設備被廣泛使用,嵌入式Web服務器則是其中關鍵的技術設備。本文介紹了Web服務器的結構設計,并對系統中采用的關鍵技術及其實現進行了論述。
關鍵詞: 嵌入式;Web服務器
Web應用程序與傳統應用程序相比,具有許多特點和優勢, 隨著Web應用程序工具與技術的快速發展,Web應用程序的應用也越來越廣泛。同時,由于Internet技術的滲透,嵌入式系統正變得越來越智能化并具有越來越多的網絡友好特性,嵌入式Web服務器的應用也越來越廣泛,它可以廣泛地用于各種監控系統、信息家電及智能家居系統、通信設備等領域[1]。
1 嵌入式Web服務器結構
嵌入式Web服務器應有如下一些的設計目標:
(1)借助HTTP協議統一并通用化設備或終端的訪問接口。
(2)實現對HTTP 1.0和HTTP l.1的支持,實現HTTP的部分方法(GET、POST、HEAD等),支持Basic、Digest加密的認證,支持服務器“推”技術等。
(3)集成簡單的應用服務器功能,便于應用開發人員方便地構建基于嵌入式Web服務器的應用系統。
(4)支持多種協作接口,嵌入式Web服務器應該可以以各種接口方式與相應的模塊進行集成,這主要是通過動態庫來實現。
(5)支持多種傳輸方式,嵌入式Web服務器需設計一個連接層,該層用來抽象各種具體的傳輸方式,提供統一和標準的連接服務,Web服務器本身只依賴一個可靠的傳輸通道,并不限定是基于TCP的。
根據以上嵌入式Web服務器的設計目標,Web服務器的核心在于其HTTP引擎和分析引擎,前者主要負責HTTP協議請求和響應消息處理,后者用于解析網頁中的嵌入式標記,以實現動態內容支持。圖1是基于嵌入Web服務器的應用系統框架,圖中的瀏覽器是客戶端,用戶接口庫是嵌入式Web服務器和設備的其他控制等部分的接口,由應用開發人員提供。虛線框中的是嵌入式Web服務器的框架結構,該設計的基本思想來源于經典的MVC(模型-視圖-控制)模型,這里把HTTP引擎和分析引擎作為控制器,待分析網頁和靜態網頁是視圖,而用戶接口庫則是作為模型,專注于業務邏輯。利用控制器來分離模型和視圖,實現模塊間松散耦合的效果,可以提高系統靈活性、復用性和可維護性[2]。
1.1 HTTP引擎
HTTP引擎主要負責對客戶訪問的過濾和權限檢查,HTTP請求和響應消息的接收和發送,會話(session)管理,客戶認證和授權,消息的封裝、解析和消息安全性檢查。
首先,HTTP引擎進行初始化工作,為該設備站點初始化相應的配置數據結構,如設置站點基本信息、建立用戶賬號、初始化各目錄的訪問權限、初始化嵌入式標記的映射定義等。然后HTTP引擎接收請求連接,提取訪問客戶的客戶端的信息(如IP等),根據配置文件的站點過濾設置進行篩選,如不允許,則返回出錯頁面,結束處理。
為了加強嵌入式應用的安全管理,嵌入式Web服務器默認設置:假定任何訪問客戶均需提供用戶名和口令,接著進行客戶認證,在客戶會話超時后的請求或初次發送請求時會要求輸入客戶的用戶名和密碼,一般在瀏覽器被關閉前或會話超時前,用戶再次訪問時不需再次提供,除非他所請求的操作需要更高的權限。客戶的用戶名和密碼是通過HTTP的401 Unauthorized響應頭部來激發客戶端的瀏覽器提示用戶輸入的。
認證通過后,HTTP引擎根據配置文件的定義給該客戶賦予相應的角色和權限,并設立客戶會話環境,便于跟蹤客戶的訪問。
當1個HTTP請求被接收后,進入HTTP引擎的處理過程。根據資源URI判斷,若客戶請求的是靜態網頁(網頁的后綴是htm或html),那么HTTP引擎在靜態網頁集中查找,加載到內存,并按照HTTP的協議規范封裝響應消息,包括各頭部和協議實體(響應的數據部分)。另外,若本網頁是采用服務器“推”技術的,其頭部信息是不同的,并與客戶端保持永久連接,此后不斷地刷新客戶端的顯示內容。HTTP引擎將封裝好的響應消息返回給客戶端,并刷新緩存。
1.2 分析引擎
分析引擎專注于待分析網頁的分析處理,實現動態頁面。其實現的傳統技術思路有以下兩種方法[3]:
(1)采用傳統的CGI方式。該方式所需的資源開銷較大,每當用戶請求CGI腳本時,嵌入式Web服務器必須初始化CGI的運行環境,導入有關參數,然后啟動其他的進程來運行CGI代碼,運行結束后,再釋放進程的相關資源,服務器需要承擔所有額外的負擔,而且和動態庫的接口也比較麻煩。
(2)使用PHP等腳本語言構建類似主機系統的Web應用服務器。當一個訪問客戶打開網頁時,服務端便執行PHP的命令,并將執行結果發送至訪問者的瀏覽器中。該方案與臺式機系統有最好的兼容性,可以充分借鑒和使用臺式機系統的現有軟件和相關源代碼。但是,該方案的實現需要很多資源,需要構建相關的PHP庫,而PHP和嵌入式系統的接口比較困難,因為PHP的設計本身是作為一種服務器端的嵌入式HTML的腳本語言,讓它直接和驅動級的動態庫等進行鏈接,實現較復雜,特別是不能很好地控制它們之間的交互。而嵌入式系統最需要的是一種實現成本小,而且比較簡單、易于使用、具有相當的靈活性和可控性,并且和動態庫有很好的配合機制。
上述兩種方式還有一個共同的缺點,就是實現業務邏輯的代碼經常和網頁的布局代碼交叉在一起,嚴重影響程序的可讀性、可維護性和可擴展性。由于屬于不同層次的代碼混在一起,會使它們的代碼的相關性大大提高,從而極不利于系統的維護。
鑒于上述問題,在嵌入式Web服務器中設計基于嵌入式標記的HTML網頁分析引擎。采用該方法設計的分析引擎的基本特點如下:
(1)視圖(頁面布局)、控制(分析引擎)、模型(接口庫)松耦合。頁面布局和接口庫可以分別獨立地進行設計和開發,前者專注于HTML頁面的布局和美化設計,后者則側重于和控制單元的交互,而分析引擎主要是協調兩者的工作。通過待分析網頁中的嵌入式標記,關聯由應用開發人員編寫動態庫中的某個函數,以此來動態生成網頁。
(2)分析引擎中集成了若干應用開發人員常用的基本功能,如用戶權限管理和口令認證、支持緩存機制、多級客戶授權、一定的安全防范措施等。在此基礎上,應用開發人員可以只專注于業務邏輯的處理和調整相關配置,就能構建和靈活調整配置、功能豐富的基于嵌入式Web服務器的系統。
分析引擎和HTTP引擎是通過共享HTTP請求和響應隊列來通信的。在分析引擎的每個運行周期中,進行如下工作:查看HTTP請求隊列是否為空,若有任務則進行分析處理,然后將結果掛入和HTTP引擎共享的響應隊列。分析引擎是周期性運行的,將其掛入運行隊列后,即可處理下個周期的請求。如果循環1個周期而沒有任務或結果,則進入睡眠。一般分析引擎是單線程,因為在它的運行過程中不大會出現阻塞。此外,作為嵌入式Web服務器,同時訪問量一般不大,即使采用多線程也不大可能顯著地提高系統的性能,而且多線程有更多的開銷。但某些應用可能需要多線程來提高系統的性能。
1.3 嵌入式標記
嵌入式標記的語法是任意連續的以空格結尾的數字或字符(除空格和圓括號)序列,設計時采用易于書寫和記憶的簡短的字母數字序列。共有兩類嵌入式標記在應用開發人員設計的待分析網頁和靜態網頁時使用。
(1)參數替換標記。該類標記用于將傳入的POST等請求的參數的值直接替換網頁中相應的參數替換標記。這類標記既是HTTP請求的參數,又可能是結果替換標記的參數。
(2)結果替換標記。該類標記用于將其代表的代碼段執行結果置換網頁中的相應結果替換標記,在置換時可能要進行類型轉換。例如,返回值是整型(int)4 000,引擎會將其轉換成字符串“4 000”,然后替換。
1.4 外部接口庫
外部接口庫是由應用開發人員提供的用于進行業務邏輯處理的動態庫中的某些函數構成的,這些函數(稱為外部函數)遵循下面描述的規則:配置文件中的映射定義部分允許應用開發人員靈活地將外部函數的運行特性和與待分析網頁中的結果替換標記的進程對應。分析引擎通過收集的外部函數的參數信息和實參值,加載指定的動態庫,搜索該外部函數的入口地址,然后構造實際的函數調用,再采集其返回值,替換相應標記,形成動態網頁。
這種思路的基本實現技術是動態裝載。過程如下:分析引擎在第1次調用該動態庫中的函數時將其加載(dlopen)到運行進程的地址空間,在庫中查找(dlsym)函數的地址,然后調用該函數,當不再需要的時候,卸載(dlclose)動態庫。
在嵌入式Web服務器啟動時,準備了另外的運行線程池,專門用于運行應用開發任務提供的函數,該線程受嵌入式Web服務器的分析引擎控制。之所以要在另外的線程中運行,是為盡量避免外部函數代碼對本引擎的影響,可以在出現異常時果斷地終止該運行線程,加上超時定時器,能將外部函數帶來的風險降低。
運行線程和分析引擎之間通過共享運行隊列和結果隊列來通信。一旦分析引擎有執行函數的需求時,就封裝1個執行結構run_struct,它定義了某次HTTP請求所需執行的所有函數及其參數、運行超時時間等信息,然后將該run_struct掛入運行隊列。運行線程是定期訪問運行隊列的,發現有任務時,就加載相應的共享庫,查找函數的入口地址,并加以執行,等待其執行結束,填充結果,直到run_struct中的所有函數執行完畢(若期間某函數執行異常,有可能導致提前結束),最后將運行完成的run_struct從運行隊列上摘下,掛入結果隊列等待分析引擎的訪問。
運行線程是等待外部函數執行完畢后,再繼續執行的。如果有多個HTTP請求等待處理,而又只有1個運行線程時,可能會有較大的延時,故可根據具體應用的實際情況,將運行線程的數量配置成多個。但不可過多,因為線程本身也要占有一定的資源,而線程切換同樣需要開銷。
2 嵌入式Web服務器的設計
嵌入式Web服務器與通用Web服務器比較,存在以下3個方面的差別[4]:
(1)運行的目標環境不一樣。通用Web服務器一般運行在計算資源和內存資源都比較豐富的臺式機上,而嵌入式Web服務器運行的目標系統大多是各類專用設備,資源比較缺乏。
(2)在各自系統中的作用不一樣。通用Web服務器主要是利用Web服務器向用戶提供信息服務,而嵌入式Web服務器嵌入在設備中,其主要作用是控制和配置設備,但也向客戶提供設備的運行信息。
(3)運行的優先級不一樣。嵌入式Web服務器作為一種監控、管理手段存在,它不能干擾設備主要任務的運行。
針對于上面嵌入式Web服務器與通用Web服務器的不同,設計嵌入式Web服務器時考慮的性能指標也不一樣。對于嵌入式Web服務器來說,吞吐率并不需要很大,而需要很快的系統響應速度,因為嵌入式Web服務器面對的用戶是少量的設備管理人員,實現的是監控與管理功能。一個好的Web服務器應具備良好的可移植性、可裁剪性和與目標設備良好的兼容性。
嵌入式Web服務器中,其Web引擎(HTTP引擎和分析引擎)是核心部分。嵌入式Web引擎的狀態圖如圖2所示。
圖2中的管理應用是嵌入式Web服務器與應用設備的接口。它用來實現獲取用戶所需的設備信息及執行實際的管理設備功能,構成監控、管理設備的用戶界面。
有時該用戶界面是靜態的,但大部分是隨時間動態改變的。如客戶請求設備狀態參數時,嵌入式Web服務器通過調用管理應用程序獲得設備動態信息,然后組織成動態Web頁面返回給客戶端;如用戶通過Web頁面發送1個控制命令字,Web服務器也需通過調用管理應用程序,把該命令相關參數傳遞給實際執行控制動作的管理程序并監視其執行,把執行結果組織成Web頁面的形式返回給用戶。在嵌入式Web服務器中實現應用程序的接口技術有公共網關技術(CGI)和服務器端包含技術(SSI)。
嵌入式系統中,Web服務器作為單獨的任務執行,任務的優先級應設置成較低的優先級,以避免對嵌入式系統主要功能造成干擾。嵌入式Web服務器的結構包括核心部分和可裁剪的功能模塊部分。核心部分包含HTTP請求分析引擎和模塊分析器。HTTP請求分析引擎負責接收客戶端發送來的HTTP請求報文,獲得客戶端信息,并把解析出的信息保存到請求結構中,后續處理模塊都從該結構中獲得請求報文的相關信息;模塊分析器則是根據配置信息調度其他功能模塊。模塊分配器執行流程如圖3所示。
RPM(Request Process Module)可以根據用戶的需求進行裁剪,它分成兩種類型:系統PRM和用戶PRM。一旦配置了系統PRM模塊,則該PRM模塊對服務器接收到的所有請求都會進行處理;用戶PRM模塊則根據進一步的配置信息,只對某些特定的請求進行處理。
針對嵌入式Web服務器采用以下措施可以提高系統性能:
(1)減小Web服務器中請求的生命周期以縮短等待時間。
(2)在Web服務器中使用線程取代進程來加強系統的并發性。
(3)采用瘦Web服務器、胖客戶機的應用模式以提升服務性能。
隨著因特網的迅速發展,需構造嵌入式Web應用系統的應用也越來越多,嵌入式Web服務器將會有很好的發展前景。
參考文獻
[1] 冀振燕.UML系統分析設計與應用案例[M].北京:人民郵電出版社,2003.
[2] CONALLEN J. Building Web applications with UML. Addison Wesley Longman,2000.
[3] 陳偉,邱書波.蓄電池生產控制網絡結構的設計與實現[J].微計算機信息,2009(1-3).
[4] DOUGLASS B P.實時UML——開發嵌入式系統高效對象[M].尹浩瓊譯.北京:中國電力出版社,2003.