彭偉
(武漢城市職業學院,武漢430064)
彭偉(副教授),研究方向為嵌入式系統開發、網絡技術、計算機算法。
傳統的Web應用在交互操作過程中頻繁出現全頁刷新的問題無法避免,即使當前頁面中僅有局部信息是需要動態刷新顯示的。這不僅影響到界面效果,在實時監測過程中還會明顯影響服務器的響應速度。
Ajax技術的出現為解決客戶端Web與嵌入式HTTP服務器之間的交互問題提供了重要途徑。Ajax是異步Javascript與XML的簡稱,這一概念由Jesse James Garrett提出,它是一組與 Web開發相關的技術,包括基于HTM L/XHTML與CSS標準的頁面表示、基于DOM的動態顯示和交互,以及基于XM LHttpRequest與服務器之間的異步通信。所有上述技術通過Javascript綁定在一起。
嵌入式以太網實時系統開發者可以嘗試通過Ajax的核心對象XMLHttp在“后臺”與嵌入式 HTTP服務器交互,對服務器發起遠程控制,讀取服務器動態返回的監測信息并刷新顯示在客戶端Web界面中的特定位置,且所有操作均不會導致當前Web界面被全頁刷新。
本文以Microchip公司的TCP/IP協議棧為基礎,討論XM LHttp對象在嵌入式Web實時系統中的具體應用方法。所選用的測試電路以PIC18F452單片機與以太網接口芯片 RTL8019AS為核心,嵌入式HTTP服務器所有Web相關文件保存在系統外部EEPROM存儲器中。
XMLHttp是Ajax技術的核心,由微軟公司在IE5.0瀏覽器中率先推出,后被命名為XMLHttpRequest。
1.1.1 創建XMLHttp對象的通用函數
客戶端與嵌入式系統HTTP服務器的所有交互都將基于在客戶端所創建的XM LHttp對象。該函數在IE中創建XMLHttp對象的語句為:

在非IE中創建XMLHttp對象的語句為:

創建XM LHttp對象后最重要的操作是設置onreadystatechange屬性(非IE中為onload),為其綁定異步回調函數。當XMLHttp對象狀態變化時,所指定的回調函數將自動處理服務器回應數據。
1.1.2 客戶端發送控制命令的函數
(1)Send_Control_CMD(URL,Html_id)
該函數可由客戶端Web中的控制命令按鈕點擊事件onClick觸發調用,它調用CreateXM LHttpObj創建XMLHttp對象,設置回調函數,然后以GET方法對 HTTP服務器發起請求。函數的第一個參數URL可以是控制命令串,也可以是CGI、HTML及其他各種Web文件名。如果要求在客戶端Web中顯示HTTP服務器返回信息,則需要設置第二個參數Html_id。例如,在發送控制命令點亮系統中某個指示燈后,要求將服務器返回的該指示燈的當前狀態顯示在客戶端。所設置的參數Html_id是客戶端Web頁中的某個容器的ID,返回信息將顯示到該容器中。如果不需要服務器回應文本信息,或對回應信息不予處理,可將該參數設為空。函數具體實現如下:

Send_Control_CMD在每次被調用時首先創建一個通用對象Obj,然后創建XM LHttp對象,并將其保存在自定義的Obj.xmlhttpobj屬性中,隨后調用XMLHttp對象的open方法與send方法,調用格式為:

其中open方法的bstrMethod參數為HTTP請求的方法,例如所選擇的“GET”方法,bstrUrl參數為請求的URL地址,在本文討論的嵌入式Web實時系統中,它用來表示控制命令串,譬如用來啟動外部直流電機的控制命令串“0?1=MOTOR”,varAsync參數用于指定當前請求是否為異步方式,默認為true,最后兩個參數提供帳號密碼,用于服務器驗證。通過open方法初始化XMLHttp對象以后,要用send方法發送請求到HTTP服務器并等待回應。由于XMLHttp對象被設為異步模式,send調用將不會被阻塞,XM LHttp對象的回調函數mReadyCall-Back將在HTTP服務器回應時異步執行。
由于Web頁中可能有多個不同按鈕要發送不同的控制命令,為簡化程序設計且便于管理對象,可將每一按鈕調用該函數創建的XMLHttp對象統一保存到全局對象數組ObjArray中。對象數組ObjArray由 Web頁中的Javascript腳本定義,即:

(2)mReadyCallBack()
它是Send_Control_CMD函數所創建的保存于對象數組ObjArray中的每個XM LHttp對象的異步回調函數,通過該函數可統一異步處理服務器回應數據。函數具體實現如下:

當ObjArray中的任意一個XM LHttp對象的就緒狀態變化時,將觸發對mReadyCallBack函數的異步調用,該函數將通過for循環掃描對象數組ObjArray,對HTTP服務器當前回應的對象進行處理。通過XMLHttp對象的responseText屬性可獲取服務器回應信息,通過Web容器的innerHTML屬性可將回應信息顯示到Web頁中。在處理完當前XMLHttp對象以后,mReadyCallBack最終將用delete釋放該對象所占用的資源。如果調用Send_Control_CMD函數時第2個參數為空,則表示發出控制命令后不需要處理服務器回應文本信息,回調函數僅僅需要釋放該對象所占用的資源。
1.1.3實現客戶端實時監測功能的函數
(1)RealTime_Monitoring()
該函數專門用于實時監測動態數據,它由Web頁面加載事件onLoad觸發調用,通過所創建的XMLHttp對象向服務器請求動態文件Status.cgi,以獲取監測數據。

其中xmlhttp定義為全局變量。
(2)aReadyCallBack()
該函數是實時監測系統外設數據函數RealTime_Monitoring所創建的XMLHttp對象的專用回調函數,它在處理HTTP服務器回應時將返回的動態監測數據顯示在ID為“txtStatus”的Web容器中,譬如<span id="txtStatus">… </span>,所返回的內容將替換其中的“…”。函數具體實現如下:


回調函數aReadyCallBack與回調函數mReadyCall-Back的差別在于:它釋放已經處理回應的XM LHttp對象(置為null)以后,接著執行了一項重要工作,即調用實時監測函數RealTime_Monitoring()。通過創建新的 XMLhttp對象,將動態請求與顯示刷新“接力”進行下去,從而使實時監測無限延續。
顯然,通過XMLHttp對象所實現的實時監測,其效果遠遠優于傳統的Web請求與響應操作模式下所使用的通過在網頁頭部加入<meta http-equiv="refresh"content="定時長度">,或者使用Javascript的setTimeout函數設置超時值,使客戶端自動按固定時間間隔請求服務器刷新顯示動態信息的方法。
有了上述以XMLHttp對象為中心的函數定義,完成客戶端Web與嵌入式HTTP服務器之間的交互操作就很容易了,例如:
①通過Web頁按鈕啟動電機,可有<input type="button"onClick="Send_Ctrl_CMD('0 ?1=MOTOR',')"value="運行">。按鈕事件觸發對Send_Control_CMD的調用,它通過XMLHttp對象在“后臺”發送命令串“0?1=MOTOR”,提交給嵌入式系統HTTP服務器處理,控制電機啟動,實現遠程控制功能。
②實時監測嵌入式系統外設狀態,可有<body on-Load="RealTime_Monitoring();">。Web頁面加載事件onLoad觸發對RealTime_Monitoring的函數調用,它同樣也通過XMLHttp對象訪問嵌入式系統HTTP服務器,不同的是它所請求的是動態文件Status.cgi。現假設所訪問的動態文件主要內容如下:

嵌入式系統HTTP服務器程序將從MPFS文件系統讀取該動態文件并將其發往客戶端。在發送過程中,HTTP服務器將對所遇到的形如“%xx”的變量碼進行解析處理。例如“%02”被定義為測試電路中AN0通道的 A/D值,“%00”“%01”被定義為兩個外接 LED的開關狀態,“%10”被定義為所控制的直流電機的啟/停狀態。經過HTTP服務器處理后的變量值將被系統當前實際的外設狀態值所替換并返回到客戶端。
由于RealTime_Monitoring函數與aReadyCallBack函數配合實現了XMLHttp對象的創建、請求、異步響應、釋放,再創建、再請求、再異步響應、再釋放等,從而借助XMLHttp對象在“后臺”實現了理想的實時監測功能。由于監測結果實時刷新顯示在Web中的特定容器位置,不會導致全頁刷新問題,這也為用戶操作帶來了良好體驗。
解決了客戶端通過XM LHttp對象在“后臺”與 HTTP服務器進行交互、發送控制命令及異步處理回應、實現實時監測功能的問題以后,接著要解決的是HTTP服務器端如何處理客戶端XMLHttp對象所發送的控制命令,以及如何處理并返回客戶端XMLHttp對象所請求的動態文件。
Microchip TCP/IP協議棧是一套服務于標準的、基于TCP/IP的應用程序,可應用于HTTP服務器、FTP服務器等,它遵循了TCP/IP參考模型,協議棧按照模塊化方式實現。Microchip整個 TCP/IP協議棧的代碼全部用C語言編寫,每層的實現代碼駐留在一個獨立的C程序文件中,服務和應用程序編程接口則通過頭文件或C程序文件定義,協議??墒褂肕CC18或 HI-TECH PICC 18編譯,圖1對比了TCP/IP參考模型與Microchip TCP/IP協議棧。

圖1 TCP/ⅠP 參考模型與Microchip TCP/ⅠP協議棧對比
為實現HTTP服務器功能,協議棧所提供的相關文件主要有TCP.c與 HTTP.c,它們分別處理客戶端與服務器端的連接及對HTTP請求的處理。在啟動嵌入式系統HTTP服務器時,主程序首先調用兩個初始化函數:StackInit()與 HTTPInit()。前者初始化協議棧,包括MACInit()、ARPInit()、TCPInit();后者初始化 HTTP 服務器,使所有的HTTP連接處于監聽狀態,受嵌入式系統資源限制,實際支持的最大連接數默認為3個。
HTTP服務器主程序接下來的主要工作是在while(1)中循環調用HTTPServer()函數,處理客戶端對HTTP服務器的請求并作出響應。HTTPServer實際執行的任務是循環掃描每個 HTTP連接,并在每個連接上調用處理HTTP請求的函數HTTPProcess()。該函數對客戶端發送的控制命令串的處理及動態文件的請求處理將分別通過回調函數 HTTPExecCmd和HTTPGetVar完成,這兩個核心回調函數由主程序具體實現。
對于客戶端Web頁內onClick事件與onLoad事件觸發的以下兩個調用示例,它們都基于XMLHttp對象,前者向嵌入式HTTP服務器發送控制命令,后者請求動態文件:

HTTPExecCmd函數對客戶端發送的命令串解碼并執行相應的操作。函數聲明為:void HTTPExecCmd(BYTE**argv,BYTE argc)。考察客戶端函數調用所發送的控制命令串:“0?1=MOTOR”。HTTP服務器函數HTTPProcess在調用HTTPExecCMD之前已經先通過HTTPParse函數由該命令串解析出“0” 、“1” 、“MOTOR”這三項內容并賦給函數參數argv,所解析出的三項的具體定義由主程序設置。
每當HTTP服務器當前所處理的CGI動態文件Status.cgi中遇到變量碼“%xx”時即調用該函數,處理動態請求。HTTPGetVar函數聲明為:WORD HTTPGetVar(BYTE var,WORD ref,BYTE*val)。該函數的val參數是待解析處理的動態文件內的某個變量的標識符,參數ref用于跟蹤返回值的狀況,參數 val用于逐個返回數據字節。
以調用RealTime_Monitoring函數為例,它通過XMLHttp對象請求動態文件Status.cgi,當HTTP服務器接收到該請求時,將從保存于EEPROM的MPFS文件系統讀取Status.cgi文件,然后由HTTP.c的SendFile函數向客戶端XMLHttp對象回傳所請求的動態文件。在回傳過程中,所遇到的動態文件內的變量將由主程序所實現的HTTPGetVar函數逐一進行處理。動態文件中的各種變量同樣將由HTTP服務器主程序進行定義。以Status.cgi文件中表示AN0通道 A/D轉換值的變量“%02”為例,由于主程序不僅循環調用HTTPServer函數響應客戶請求并處理回應,在循環中還會分時處理外設操作,包括所需要執行的AN0通道的A/D轉換操作。通常所有這些相關操作被集中放在處理I/O的函數ProccessIO()中實現?,F假定RA0引腳外接可變電阻器RV1,則AN0通道的A/D轉換具體實現如下:

每一次的A/D轉換值都被刷新保存在AN0String字符串中,以便發往客戶端顯示。當 HTTP服務器的HTTPProcess函數所調用的SendFile函數當前遇到了變量“%02”,它會將其交由HTTPGetVar函數處理。所輸入的第1個參數var為2,它由變量“%02”轉換為BYTE類型得到,用于標識當前變量要獲取的是AN0通道的A/D轉換值。
現假設AN0String當前獲取的 A/D值為“709”,HTTPGetVar函數可通過以下關鍵語句返回A/D值:

其中ref初始時默認為0。顯然,該函數將被連續調用3次,每次調用時 ref遞增,直到通過*val返回最后一個字節以后,通過返回HTTP_END_OF_VAR告知Send-File函數當前變量處理結束。對于待返回到客戶端的數據字節,HTTP將通過調用TCP層提供的函數TCPPut及TCPFlush,通過指定的Socket套接字將數據字節發往客戶端,由客戶端XMLHttp對象的異步回調函數通過responseText屬性讀取并刷新顯示在 Web中的特定位置。
通過仿真及實物電路測試表明,使用Ajax的XMLHttp對象及Microchip TCP/IP協議棧,可以很好地解決以太網環境下Web操作界面與嵌入式控制系統的交互問題,實現對基于 HTTP服務器模式的嵌入式系統進行遠程控制及實時監測,且能夠將所有相關操作保持在穩定的瀏覽器窗口中執行。
編者注:本文為期刊縮略版,全文見本刊網站www.mesnet.com.cn。
[1]XM LHttpRequest[EB/OL].[2011-03].http://en.wikipedia.org/wiki/XMLHttpRequest.
[2]Ajax(programming)[EB/OL].[2011-07].http://en.wikipedia.org/wiki/AJAX.
[3]Microchip TCP/IP Stack[EB/OL].[2011-07].http://www.microchip.com.
[4]王凈.AJAX技術和Web應用[J].艦船電子工程,2009(11).
[5]張榮光.基于XMLHT TP的桌面程序與WEB服務器間通訊的研究[J].科技信息,2010(33).
[6]安佰秀.基于以太網和嵌入式Web服務器的監控系統設計[J].工礦自動化,2011(5).
[7]郁繼宗,彭樹生.基于PIC單片機的以太網數據采集與控制電路設計[J].微計算機信息,2005(2).
[8]范郁寶.基于嵌入式服務器在監測控制中的應用[J].自動化儀表,2011(5).