天天看點

原創翻譯 在Windows CE上實作一個全功能的webserver

本文轉載自微軟嵌入式中文社群 www.msembed.com

摘要

當開發人員在Windows CE上實作一個webserver時,他們通常會想到要實作PC平台上的webserver有的大多數的功能。但是對于Windows CE IIS來說這不可行。Windows CE IIS對于有些功能特性不支援,例如過程标号(session ID).本文描述了如何通過網際網路伺服器應用程式程式設計接口(ISAPI)來實作這些功能特性。最後,文章用一個例子來說明如何來做這件事情。

結構圖

Isapi擴充動态連接配接庫

Windows CE IIS不支援Web伺服器有時需要的兩項功能,它們是

  • 事務間的狀态(States between Transactions)
  • 過程标号的管理

ISAPI(Internet server application programming interface)擴充可以使我們支援這些特性。以下部分是怎樣來實作。

ISAPI被開發出用來給應用程式開發人員一個有力的方法來擴充IIS的功能。為了生成Windows CE Web Server的ISAPI擴充,需要編譯生成一個動态連接配接庫,該動态連接配接庫導出如下标準ISAPI入口:

GetExtensionVersion

HttpExtensionProc

TerminateExtension (可選)

GetExtensionVersion在動态連接配接庫第一次被裝載時被調用,HttpExtensionProc在每個接入請求來到時都被調用,TerminateExtension在動态連接配接庫被解除安裝時被調用。和Web伺服器的互動通過标準的ISAPI回調函數來進行,比如ReadClient和WriteClient等。

因為所有的請求都隻被這個動态連接配接庫處理,是以以下功能可以被實作:

  • 過程标号(Session Id)的管理
  • 提供登入認證
  • 發送定制化檔案
  • 一些實時變量,例如CPU的溫度、使用情況、風扇轉速、連結的裝置和IP設定等都可以輕松地通過調用對應的API而獲得并嵌入頁面中。

怎樣裝載ISAPI擴充動态連接配接庫

 除了編譯過程中加入web server元件外,還需加入以下的系統資料庫項來實作動态連接配接庫的自動裝載:

[HKEY_LOCAL_MACHINE/COMM/HTTPD/VROOTS//]

  @="

//windows//sampleisapi.dll

"

"a"=dword: 0 ;用于移除認證

 Web伺服器在收到來自任意用戶端的一個請求後将裝載此動态連接配接庫。此動态連接配接庫可以處理任意數量的用戶端的請求。

被導出的函數

 HttpExtensionProc在每個請求到來後都被調用。對此請求的處理在此函數中進行。

 1.GetExtensionVersion

此函數在動态連接配接庫第一次被裝載時調用。

2.HttpExtensionProc

這是此動态連接配接庫唯一重要的函數。此函數在每個請求到來後都被調用。GetServerVariable函數可以用來獲得查詢字元串值,根據收到的查詢結果,用WriteClient 函數可以将相應的被請求檔案寫回到用戶端。若需從用戶端讀取資料,可以使用ReadClient函數。

 此函數的原型如下:

DWORD WINAPI HttpExtensionProc (LPEXTENSION_CONTROL_BLOCK lpECB);
這裡的 LPEXTENSION_CONTROL_BLOCK 被聲明如下.:

typedef struct _ EXTENSION_CONTROL_BLOCK 

{

DWORD cbSize; 

DWORD dwVersion; 

HCONN ConnID; 

DWORD dwHttpStatusCode; 

CHAR lpszLogData[HSE_LOG_BUFFER_LEN]; 

LPSTR lpszMethod; 

LPSTR lpszQueryString; 

LPSTR lpszPathInfo; 

LPSTR lpszPathTranslated; 

DWORD cbTotalBytes; 

DWORD cbAvailable; 

LPBYTE lpbData; 

LPSTR lpszContentType; 

BOOL (WINAPI* GetServerVariable); 

BOOL (WINAPI* WriteClient); 

BOOL (WINAPI* ReadClient); 

BOOL (WINAPI* ServerSupportFunction);

} EXTENSION_CONTROL_BLOCK, LPEXTENSION_CONTROL_BLOCK;

3.TerminateExtension

此函數在動态連接配接庫被解除安裝時調用。  

GetServerVariable

GetServerVariable函數被用來擷取伺服器變量,例如IP位址,查詢字元串等。

1.原型

BOOL WINAPI GetServerVariable(HCONN hConn, LPSTR lpszVariableName, VOID lpvBuffer, LPDWORD lpdwSizeofBuffer );

2.參數

hConn

指定連結句柄。這是HttpExtensionProc函數的輸入參數。

lpszVariableName

一個NULL結尾的字元串用以标明被請求的伺服器變量。

lpvBuffer

指向接受被請求資訊的緩沖區。

lpdwSizeofBuffer

指向一個DWORD變量,該變量表明了lpvBuffer指向的緩沖區的大小。在成功調用後,此DWORD值為傳到緩沖區的位元組數目,包括Null結尾位元組。

一些可以用GetServerVariable函數來擷取的重要變量如下:

PATH_INFO 由用戶端給出的URL的尾部路徑資訊。

QUERY_STRING 指定了URL中的第一個問号後的資訊。

REMOTE_ADDR 指定了用戶端的IP位址。

實作示例

正如已經提到的,ISAPI擴充動态連接配接庫的主要用途是管理過程标号(session id)和獲得一些實時參數如IP位址設定等。

1.用字元串參數調用外部動态連接配接庫并将傳回結果插入到發送給用戶端的HTML輸出中

我們剛才已經提到,要發送給用戶端的html和java腳本檔案是在儲存設備上已有的。現在在存儲這些檔案之前,一些特殊符号可以被包含在html檔案中來提示ISAPI動态連接配接庫這些符号應被替換為一些實時變量。例如以下格式可以被包含在html檔案裡

!!DllName!!FunctionName!!

例如如果你想顯示裝置的IP位址,你可以加入如下的符号序列來告訴ISAPI将此符号序列替換為IP位址。

!!NetStatusDll!!GetIPAddress!!

在将檔案發送到用戶端之前,ISAPI動态連接配接庫會解析檔案中的符号序列。當找到以上序列後,将替換序列中的DllName和FunctionName。裝載動态連接配接庫後将調用解析到的函數,并将序列替換為函數傳回的字元串。在上面這個例子中,NetStatus.dll通過調用LoadLibrary API被裝載,函數GetIPAddress的位址通過調用GetProcAddress API而獲得,最後函數GetIPAddress被調用。

同樣地,當使用者希望設定裝置上的實時變量時,發出的消息資料也可以包含符号序列。例如如果使用者希望從遠端用戶端為裝置設定IP位址時,帶有DllName和FunctionName的符号序列可以被加入到點選網頁上的某個按鈕時發出的消息資料中。

2.管理過程标号

    可以生成下表來管理過程标号:

  IP位址   過程标号   最後的Tick數 (ms)
   176.234.11.23    12avcdefdef    10000
   23.123.45.6    234rfvdadds    23456
   145.67.89.90    123456asdfg    45678

 當從一個新的用戶端(例如新的IP位址)收到請求後,一個随機過程标号被生成并配置設定給該IP位址,同時此标号被存入XML資料庫中。不論什麼時候從任何用戶端收到請求後,該表中的資料将被檢查,如果對應的用戶端項已存在于表中,則網頁内容将被發送至用戶端。如果用戶端項不存在,那麼隻有登入頁面被發送至用戶端。表中的最後Tick數可以用來判斷過程是否逾時。

 總結

 本文解釋了Isapi擴充動态連接配接庫的用法。Isapi擴充動态連接配接庫多用于需要使用一些實時變量如CPU溫度,IP位址設定等的網頁檔案中。