本文转载自微软嵌入式中文社区 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 | ||
| ||
} 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地址设置等的网页文件中。