一、引言
isapi与cgi都属于通用的网关接口,主要用来实现www服务器与客户端的信息交互。
随着www爆炸式的发展及其日益普及,人们的眼光已被充斥其上的商机所吸引。在www上求取经济利益的方式主要有以下几种:
通过为企业等作广告宣传收取广告费;
向入网观看者收取订阅费;
直接在网上出售商品和服务。
目前大多数网站提供信息的方式是由用户通过客户浏览器(如netscape或explorer等)与www服务器连接,然后用鼠标点按超连接以浏览相关主页。在此过程中,基本上是服务器向客户端单方向的信息传递,随着服务需求的不断扩大,这种单纯的单方向传递信息的静态主页已不能满足需求。不论是服务提供方还是客户,都希望浏览服务器将信息发送到用户同时,用户端也能将信息发送到服务器端,实现服务器与客户的交互。典型的应用如:用户登记表、用户留言板以及用户通过www检索服务器端的数据库等。
要实现一个可与用户交互信息的服务系统,所需增加的有两项:交互式主页和用户输入信息处理程序。交互式主页即有输入信息的编辑框,选择菜单按钮之类的主页,以供用户输入信息;用户输入的信息则交由用户信息处理程序处理。实现该程序可以有多种途径,该程序可以放在服务器端,也可以放在客户机端,前者如cgi、isapi,后者如javaapplet等。本文只讨论前者,将阐述isapi的优点,并就其实现举例说明。
二、web交互环境的实现
2.1交互式主页
要实现web上的交互环境,用户必须能够在他浏览到的主页上输入信息,这就是一个交互式的主页。一般来说,用户输入信息的形式有填写编辑框,点选无线按钮等选择框及选择下拉菜单等,所以交互主页也必须有这些输入元素项。下面是一个简单的交互主页例子:
交互式主页html源文件:isapi1.htm
「html」
「title」test「/title」
「head」
isapitest
「/head」
「body」
「formaction="/gjy/isapi1/debug/isapi1.dll?registeruser"method=post」
inputyourregisterinfomation:「br」
name:「inputtype="text"name="first"」「br」
address:「inputtype="text"name="middle"」「br」
email:「inputtype="text"name="last"」「br」「p」
「inputtype="submit"」
「inputtype="reset"」「/p」
「/form」
「/body」
「/html」
通过explorer浏览器打开该文件,可以看到如下效果(编辑框中已输入内容):
2.2实现交互主页的途径。
从上述主页制作描述可见,一个交互式主页的制作是很简单的,但要真正实现与用户的交互,还必须要有应用程序的参与。这个程序可以属于多种样式,如cgi、javaapplet以及isapi。在上述主页文件中,有一项:
「formaction="/gjy/isapi1/debug/isapi1.dll?registeruser"method=post」
这里就指明了对应处理该主页输入信息的程序(isapi1.dll),这是isapi的应用程序动态连接库。对于cgi应用程序也是一样的处理。
一般来说,该程序的功能就是要将用户输入信息传到服务器应用程序。
cgi是大家都比较熟悉的一种实现上述功能的有效途径,也可能是当前最为流行的一种,而isapi是微软独特的具有类似cgi功能的网络应用接口标准。isapi在性能上较之cgi具有许多优良特性。下面我们简单介绍一下cgi与isapi以及它们之间的性能差别。
三、cgi原理及其性能
3.1cgi概念
cgi即通用网关接口(commongatewayinterface),它是一个www服务器
主机对外服务的标准接口,一般来说,一个cgi接口的功能就是在超文本文件和服务器主机应用程序间传递信息。
3.2cgi程序语言
事实上,任何一种程序语言,只要能在服务器主机上利用cgi接口来编写应用程序,都可以叫作cgi程序语言。目前最为流行的cgi程序语言有四种:c,shell,perl和visualbasic,其它一些语言也有许多人在用,如tcl,fortran及applescript等。
3.3cgi程序的执行
cgi程序一般是个可执行程序。编译好的cgi程序一般要集中放在一个目录下。具体存放的位置随操作系统的不同而不同,例如unix系统下是放在cgi-bin子目录下,而在windows操作系统下(注意,这里不包括nt4.0)以webstar或website作www服务器,cgi程序都放在cgi-win下。cgi程序的执行一般有两种调用方式:1是通过url直接调用,如:“http://202.114.2.182/cgi-win/cgi.exe”,在浏览器的url栏里直接写入上述描述就可以调用该程序;另一种方式,也是主要的方式,是通过交互式主页里的form栏调用,通常都是用户在填完一张输入信息主页后按确认按钮启动cgi程序,前面的交互主页就是一个如此调用cgi的典型例子。
3.4cgi工作的主要流程
cgi工作的主要流程是:1.一个用户请求激活一个cgi应用程序;2.cgi应用程序将交互主页里用户输入信息提取出来;3.将用户输入的信息传给服务器主机应用程序(如数据库查询〕;4.将服务器处理结果通过html文件返回给用户;5.cgi进程结束。
3.5cgi的性能评价
cgi的跨平台性能极佳,几乎可以在任何操作系统上实现,如dos、windows、unix、os/2、macintosh等。实现cgi的编程语言也有很多选择。cgi的应用程序一般都是一个独立的可执行程序,和www服务器各自占据着不同的进程,而且一般一个cgi程序只能处理一个用户请求。这样,每有一个用户请求,都会激活一个cgi进程,当用户请求数量非常多时,会大量挤占系统的资源如内存,cpu时间等,造成效能低下。
四、isapi原理及其性能
4.1isapi概念
isapi即internetserverapplicationprograminterface,是微软提供的一套面向internet服务的api接口,它能实现cgi能提供的全部功能,并在此基础上进行了扩展,如提供了过滤器应用程序接口。
4.2isapi程序语言
由于开发isapi应用要用到微软的一套api,所以能用来开发isapi应用的语言不如cgi那么多。主要有visualc++4.1以上版本,visualbasic5.0、borlandc++5.0也可以。
4.3isapi原理
isapi的工作原理和cgi大体上是相同的,都是通过交互式主页取得用户输入信息,然后交服务器后台处理。但是二者在实现机制上大相庭径。isapi与cgi最大的区别在于:不同于cgi,在isapi下建立的应用程序是以动态连接库的形式存在;而cgi的应用程序一般都是可执行程序。
4.4isapi程序的执行
isapi应用的工作流程与cgi有一些不同。isapi应用的dll不仅可以象cgi程序一样被用户请求激活,还可以被系统预先激活来监视用户输入;对于被用户激活的dll,在处理完一个用户请求后不会马上消失,而是继续驻留在内存中等待处理别的用户输入,直到过了一段时间后一直没有用户输入。
4.5isapi性能评价
一个isapi的dll,可以在被用户请求激活后长驻内存,等待用户的另一个请求,还可以在一个dll里设置多个用户请求处理函数,此外,isapi的dll应用程序和www服务器处于同一个进程中,效率要显著高于cgi。
不过isapi的平台兼容性较差,目前只能用于微软自己的windows95和nt操作系统上,服务器平台也仅限于iis(internetinformationserver)和mspersonalwebserver以及ntworkstation上的peerwebserver。
五、isapi的实现
能够支持isapi开发的平台只有微软的几个平台组合(如nt+iis,win95+mspersonalwebserver)。因此开发isapi只能这几个平台上。开发语言前已有述,这里向大家推荐visualc++4.2版,它的wizard提供了专门制作isapi的功能项。
下面是个简单的例子,功能是将用户从浏览器上的输入简单地回显给用户,功能简单,但是具备一个典型的isapi全部流程。源程序如下(大部分为wizard生成的代码):
1.主程序:
//isapi1.cpp-implementationfileforyourinternetserver
#include"stdafx.h"
#include"isapi1.h"
///////////////////////////////////////////////////////////////////////
//theoneandonlycwinappobject
//note:youmayremovethisobjectifyoualteryourprojecttono
//longerusemfcinadll.
cwinapptheapp;
///////////////////////////////////////////////////////////////////////
//command-parsingmap
begin_parse_map(cisapi1extension,chttpserver)
/*************mycodesbeginhere***********/
on_parse_command(registeruser,
cisapi1extension,its_pstrits_pstrits_pstr)
on_parse_command_params("firstmiddlelast")
/*************mycodesendhere***********/
end_parse_map(cisapi1extension)
///////////////////////////////////////////////////////////////////////
//theoneandonlycisapi1extensionobject
cisapi1extensiontheextension;
///////////////////////////////////////////////////////////////////////
//cisapi1extensionimplementation
cisapi1extension::cisapi1extension()
{
}
cisapi1extension::~cisapi1extension()
{
}
boolcisapi1extension::getextensionversion
(hse_version_info*pver)
{
//calldefaultimplementationforinitialization
chttpserver::getextensionversion(pver);
//loaddescriptionstring
tcharsz[hse_max_ext_dll_name_len+1];
isapiverify(::loadstring(afxgetresourcehandle(),
ids_server,sz,hse_max_ext_dll_name_len));
_tcscpy(pver->lpszextensiondesc,sz);
returntrue;
}
///////////////////////////////////////////////////////////////////////
//cisapi1extensioncommandhandlers
/******mycodebeginshere**********/
voidcisapi1extension::registeruser
(chttpservercontext*pctxt,lpctstr
pstrfirst,lpctstrpstrmiddle,lpctstrpstrlast)
{
//doprocessinghere!
*pctxt<<_t("yournameis:");
*pctxt<<_t(pstrfirst);
*pctxt<<_t("\n");
*pctxt<<_t("youraddressis:");
*pctxt<<_t(pstrmiddle);
*pctxt<<_t("\n");
*pctxt<<_t("youre_mailis:");
*pctxt<<_t(pstrlast);
}
/*********mycodesendhere**********/
//donoteditthefollowinglines,
whichareneededbyclasswizard.
#if0
begin_message_map(cisapi1extension,chttpserver)
//{{afx_msg_map(cisapi1extension)
//}}afx_msg_map
end_message_map()
#endif//0
2.主头文件
//isapi1.h-headerfileforyourinternetserver
//isapi1extension
#include"resource.h"
classcisapi1extension:publicchttpserver
{
public:
cisapi1extension();
~cisapi1extension();
//overrides
//classwizardgeneratedvirtualfunctionoverrides
//note-theclasswizardwilladdandremovememberfunctionshere.
//donoteditwhatyouseeintheseblocksofgeneratedcode!
//{{afx_virtual(cisapi1extension)
public:
virtualboolgetextensionversion(hse_version_info*pver);
//}}afx_virtual
//todo:addhandlersforyourcommandshere.
/***********mycodedbeginhere(函数声明)*********/
voidregisteruser(chttpservercontext*pctxt,
lpctstrpstrfirst,lpctstr
pstrmiddle,lpctstrpstrlast);
/*********mycodesendhere
declare_parse_map()
//{{afx_msg(cisapi1extension)
//}}afx_msg
};
3.动态连接库定义文件
/*************************************/
/*isapi1.def*/
/*************************************/
;isapi1.def:declaresthemoduleparametersforthedll.
library"isapi1"
exports
httpextensionproc
getextensionversion
在上述程序中,定义了一个chttpserver的类cisapi1extension,这是该程序的主要一个类,通过它实现与用户交互的功能。由on_parse_command段实现函数映射,上述程序中定义了该dll中的一个成员函数registeruser,其功能就是将用户在编辑框中输入的信息发送回用户。关于具体实现细节,可以参看vc4.2帮助文档。
将上述文件编译成dll后放入服务器主机内www服务器指定的用户有执行权限的scripts目录里,该目录的逻辑名应和交互主页里的一致。设置完后,通过浏览器连到服务器上,浏览该主页,并输入信息到编辑框中。