Delphi 6 Web Services初步评估
这是我刚到现在公司的时候(2001年8月份)所作的一份测试报告,现公布出来,希望能对大家有所帮助。因为当时d6刚刚发行,Web Service方面还存在一些问题,当前的update 1 for D6已经发布,主要就针对Web Service做了大量的修改,已经能与MS相关的Web Service兼容了。可能下面文章内提到的部分内容在Update1有所变动,在此说明!
2000年6月22日,整个IT行业期盼着一个令人向往的新时代,因为今天美国微软公司正式对外宣布了.Net战略,并且确定每年为这个新的战略投入40亿美元的研发费用。.Net的思想彻底地把计算模式从单机、客户机/服务器和Web网站的方式转向分布式计算(Distributed Computing)。虽然DCOM和Corba是当今比较流行的分布式对象模型,然而它们都存在着仅能用于本地网络这个局限性,很难突破防火墙的限制,因此不能把整个互联网作为一个计算资源体系加以利用。.Net则通过一种称为Web Services的技术把分布在互联网上的各种资源有效的通过编程手段整合在特定的应用界面里。
作为.Net的核心概念,Web Services是目前炙手可热的技术,各大厂商,如Microsoft、IBM、SUN等莫不投入大量的资源以求站在领导地位。Borland公司于2001年6月份发布的最新的RAD工具Delphi 6.0,并且把支持Web Service开发作为最大的卖点。近日,我对Delphi6创建Web Services程序进行了初步的测试和评估。
一、 Web Service概述:
Web Services就相当于过去我们编程中常常调用的API函数和在面向对象编程中调用
的接口,只不过API存在于本机上,接口通常存在于本机或者本地局域网内,而Web Services则将无所不在地分布在整个互联网络上。
Web Services可以真正的实现跨平台远程过程调用RPC(Remote Process Call),无论采用何种操作系统,无论采用何种构架的硬件,无论采用什么语言调用,都能够处理它的的调用请求。因为Web Services是由SOAP(Simple Object Access Protocol)作为封装协议,HTTP(Hypertext Transfer Protocol)作为通讯协议组成,并且通过WSDL(Web Services Discription Language)描述服务接口等信息。
SOAP,定义了客户端调用服务器端接口方法的一种机制。由于SOAP是基于扩展标记语言XML(Extensible Markup Language)标准文档方式,因此它可以轻松的实现跨平台,它使用XML定义了一套编码规则,用于网络上传输调用请求信息以及回应信息。
HTTP,作为WWW(World Wide Web)所使用的通讯协议,因为防火墙对各个端口进行监控,而HTTP使用的80端口用于Internet访问,通常防火墙不会限制此端口通信,所以一般可以通过防火墙,与连接在互联网上的机器通信。
WSDL,用于描述当前Web Service的各种信息,以便与客户端通过WSDL来取得调用接口的信息。
二、 评估测试过程:
整个评测的目标是验证Delphi 6对建立Web Services工程的支持程度,Web
Services的工作效率,以及与其它厂商Web Services的整合兼容性。
★ 测试环境:
CPU:PIII 550
内存: 256MB
OS: Windows2000 Server + SP2
Web Server:IIS 5.0 + SP3
开发环境:Borland Delphi 6.0 Enterprise
Microsoft Visual Studio 7.0 Beta 2
Microsoft SOAP TOOLKIT 2.0
★ 基本测试过程:
Web Services通过接口方法调用返回值来获取调用结果,因此测试程序通过调用不同类型返回值的接口方法来作为测试方向,分为以下四种:字符串类型返回值,对象类型返回值,对象数组类型返回值和二进制文件返回值。
1、 TEST1(字符串类型返回值方法调用):
首先采用Delphi 6创建一个Web Services工程,Delphi 6通过向导自动生成一个单元,此单元包括了Web Services通讯所需要的各个控件:THTTPSoapDispatcher用于响应基于SOAP的请求,并转交给其它的处理控件;HTTPSoapPascalInvoker用于从THTTPSoapDispatcher接收SOAP消息,并进行分析调用合适的接口方法,最后对接口调用返回结果进行封装(Encode);TWSDLHTMLPublish则是用于公布描述此Web Service接口的WSDL文档。
要为Web Service服务提供接口方法,需要建立一个从IInvokable继承的接口,以及从TInvokable继承的实现此接口的对象。
下面,我们就可以为这个Web Service添加方法了。在这第一个评估测试中,我们需要添加一个字符串类型作为返回值的方法,而且为了尽量准确的测试响应效率,我们希望能传输比较大数据量的字符串。因此创建了一个1024个‘Hello, The World!’组合的字符串作为方法的返回值。
调用结果如图一所示:
(图一)
客户端的调用,顺利取得了服务器端的字符串并显示出来。毕竟服务器对返回值的编码也是文本类型,所以说码耗费的时间并不多,因此整个请求的效率还是可以让人满意的。
当然,正是因为Web Services是基于SOAP的,传递文本自然是“拿手好戏”,但在 我们实际应用中,需要的结果通常来说不是字符串文本,而是别的信息,为了继续
证明Web Services将会带给我们的惊喜,我进行了下一个测试。
2、 TEST2(对象类型返回值方法调用):
在实际应用中我们常常会遇到客户端需要的是从服务器端返回数据库查询结果,在这种情况下,返回的数据可能是各种类型数据的组合,这个测试将会告诉我们如何通过Web Services传递复杂类型资料信息。
传递的复杂类型资料信息可以通过对象进行封装,便于创建于使用中的管理,更重要的是因为Delphi“强迫”我们不得不这样做。在Delphi 6中,如果接口返回值为对象,则此对象必须是从Tremotable类继承下来,并且对客户端能访问的成员变量必须作为属性公布。
针对测试,我创建了一个从Tremotable继承的类TXSPerson,并且公布了六个属性:ID、Name、Age、Gender、Content、Email。因此我可以在客户端通过方法访问这个类实例的这六个成员变量的值。在服务器端,我分别对这六个值进行了赋值,并把类作为方法的返回值。客户端的调用此方法得到TXSPerson类型的对象实例,从而访问它的个属性值。
调用结果如图二所示:
(图二)
从上面的结果可以看出,传输对象的效率就没有传输字符串高了。首先一点,在服务器端程序和客户端程序都必须管理一个类,相对于传递字符串多了这些类的管理开销,自然影响了效率。
从这个测试中,我们可以传递复杂类型的资料了,对于绝大多数的实际应用来说,每次传递已比资料是不够的,我们可能需要的是大量的数据库记录传递。在Web Services中,可以通过使用动态数组来实现,正如下一个测试。
3、 TEST3(对象数组类型返回值方法调用):
当服务器端的一大笔数据库记录需要传递给客户端,每一条记录作为一个对象实例保存,所有的记录用一个对象数组保存,并且以对象数组作为返回值传递到客户端。在这个测试中,我采用了与数据库结合的方式进行测试,以便于去更真实的模拟实际的应用。数据库我采用了Access2000,通过ADO(Microsoft ActiveX Data Objects)进行连接访问,并创建一个动态数组保存查询的各个字段的结果,作为返回值返回到客户端。
调用结果如图三所示:
(图三)
可以看出来,调用仍然非常顺利,客户端获得了期望的资料纪录。但是相对于传输一条记录来说,效率再一次的降低了。应该说来是因为动态数组的原因导致了效率的降低,动态数组是Delphi的一个特征,在C/C++中是没有动态数组的,所以C/C++中数组的内存都是在编译期间分配的。而Delphi中引入了动态数组,这使得只能在运行期间动态的分配内存,从而导致了对动态数组管理所引起的开销,影响效率。
在实际应用中,有时候我们需要传递文件,例如说数据库里面的图片,通过Web Services应该怎么实现呢?作为一种简单的解决办法,我们再一次求助于动态数组。
4、 TEST4(二进制文件返回值方法调用):
在最后一个返回值类型测试中,为了测试Web Services对文件的传输能力,我通过方法结果传递一个JPEG的图片。要使客户端能接收到服务器端的图片,必须采用某种标准返回值类型来组织图片的内容,在测试中使用了动态数组TbyteDnyArray作为返回类型。
服务器端通过TfileStream读取出图片文件的内容,并拷贝到TbyteDnyArray数组中,客户端接收到TbyteDnyArray类型的数组后使用TmemoryStream写回到文件中去,从而完成了文件的传输过程。
调用结果如图四所示:
(图四)
功能的确实现了,但是测试的结果却让人大吃一惊,虽然也猜想到,采用如此“巨大”的动态数组会对效率产生比较大的影响,事实也的的确确也证明了,这种方式实现文件传输的方法是不可行的。
毫无疑问,如此低下的效率正是因为动态数组的开销所导致,对于15KB的图片来说,动态数组将为它的每一个字节生成一个元素,系统的内存管理终究也显得如此“捉襟见肘”。
虽然采用这种方法传递文件我们“失败”了,但是并不是说明没有高效率的传递文件的办法。作为二进制的文件,如果要作为Web Services的返回结果传递在网络上,就必须把二进制文件存放在SOAP信息中,SOAP却是文本文件,所以对于二进制文件作为文本文件再网上传输,完全可以采用已经成熟的协议了,最常用的莫过于MIME(Multipurpose Internet Mail Extension protocol)了。通过Base64编码或其他方式对图片进行编码以后,传递到客户端以后,在进行Base64的解码,效率将会数十倍的提高。但是因为Delphi 6虽然提供了Base64编码解码,但是因为一些不完善的原因使我放弃了对这个方法的测试。
★ 测试总体印象:
在整个测试中,对Delphi 6创建的Web Services有以下几个印象:
1、 客户端应用程序连接服务器端Web Service的时候,第一次调用很慢,而以后的调用明显加快。
图五显示了调用各个接口第一次和第二次的传输速率(每秒钟传输千字节数KB/S)。
由此可以看出,第一次的方法调用非常耗时,可能达到第二次调用的8倍,因此可以确定,第一次调用接口的时候,大量的操作事件耗费在连接的建立上面。一旦连接建立,以后的调用速度会大大加快。
(图五)
从图五中,也能明显的看到各种不同返回类型测试的效率高低。
2、 抛开第一次方法调用耗时以外,某些方法每次调用测试数据传输速率不稳定。例如测试TEST1和TEST2中,基本上速率为850KB/S或者1134KB/S,而TEST3的传输速率变化则非常广,从401KB/S到530KB/S都随机出现,而TEST4的测试因为速率太小,可能导致比较大的误差,在此不做考虑。
TEST1、TEST2相对测试比较稳定,是因为服务器端是直接返回了所需要的值,速率的变化仅仅来至于传输过程。而TEST3中必须从数据库中读出数据,并且创建了动态数组来传递资料,因此出现速率影响因素较多,导致传输速率变化比较大。
★ Web Services兼容性问题测试:
正是由于Web Services的火热,导致各家大厂商闻风而动,并且推出自己相关的概念,建立自己的方案。例如SUN公司推出ONE (Open Net Environment)的概念对抗微软,Oracle公司则以Dynamic Web Service的概念表示与微软抗衡。
SOAP的规格在不断的发展,从0.9、1.0到现在的1.1。但是,目前市面上提供SOAP功能的软件并不一定都符合最新的SOAP规范,即使是支持相同SOAP版本规格的软件,对于如何实现可能都有一些差异。但是,可能正是由于这一些细微的差异可能造成软件开发人员的困扰,更何况Web Services是以SOAP为基础的沟通技术。因此,如果不同SOAP软件接口对于SOAP规格的实现有所不同,将会造成客户端应用程序无法和Web Service沟通,或是在Web Service和Web Service之间无法使用彼此提供的服务。这样将会失去SOAP和Web Services技术的精髓。
下面的测试采用了当前最流行的两个平台进行兼容性测试,Microsoft Visual Studio 7 Beta 2版本,和刚刚发行的Delphi 6 Enterprise。
在前面的测试中,我采用Delphi 6创建Web Services,并用Delphi 6开发客户端进行连接,整个过程非常完美。然而现在,我们的测试一下是否当前最火的两个开发工具能“和平共处”呢?
首先,我在VS7环境下面,使用C#创建了一个Web Services,提供一个方法AddXY( int x, int y);然而当我在Delphi中调用的时候,很让人失望,出现了如图六的调用错误:
(图六)
看来,VS7和Delphi6还不能很好的合作到一起。当使用MST2(Microsoft Soap Toolkit 2.0)带的追踪工具Trace Utility拦截HTTP信息,察看传递的SOAP信息。发现VS7开发的Web Services的SOAP和Delphi6开发的Web Services的SOAP有一些不一样。正是因为这些格式的不一样,导致了它们之间沟通的失败。
而且不但SOAP格式不太一样,连WSDL的格式都大相径庭,以至于Delphi 6导入刚才我们在VS7下写的方法public int AddXY(int x, int y)以后,生成的接口声明如下:procedure AddXY(var parameters: AddXY); stdcall;因此产生了很让Delphi自己“尴尬”的事情,这是一个procedure而不是function,调用这个方法没有返回值,也就是得不到方法调用的结果,虽然生成的接口方法中参数parameters为AddXY类,并且是一个var类型的参数,可惜,很遗憾,客户端所需要的结果并没有包含在AddXY类中。而Delphi为这个方法声明了一个结果类AddXYResponse,可是我们却无法通过调用方法得到这个对象实例。通过进一步对接口描述文件WSDL的分析,发现Delphi 6对WSDL文件的解释存在某些BUG,导致了生成接口声明出现错误的问题。
总的来说,当前Microsoft和Borland之间的Web Services方案看来还是存在着很大的不同点。但是这并不是说我们就不能在delphi下面调用VS7创建的Web Services方法。我们还是可以通过MST2提供的COM接口进行访问。通过我的测试,这种方法没有问题,能够顺利的调用VS7的Web Services的各个方法,毕竟MST2和VS7 Beta2都是微软的产品。
当然,它们之间的不兼容,让我们很伤脑筋,作为当前的两大主流开发环境,竟然不能让我们体验到Web Services跨平台、跨语言的优越性,实在让人有些失望。
毕竟SOAP和Web Services标准以及技术仍然处于快速的发展之中,因此目前各家实现的细节可能会稍有不同,也许等到SOAP功能规格成熟之后,就不会再有这些恼人的细节问题。据资料介绍,Delphi 6的Web Services是能够顺利的整合到许多由Java实现的Web Services或是Java客户端应用程序,看来,Borland Delphi 6的Web Services实现还是偏向于IBM的阵营!
★ 创建Web Services的技巧:
1、 IIS 5中的相关设置:
因为Delphi 6创建的Web Services是一个ISAPI(Internet Server Application Programming Interface)程序,所以必须使用IIS作为它的服务器。在实际的开发和应用中,应该注意一下关于IIS5中针对ISAPI的缓存设置问题。
启动Internet服务管理器,选择Web站点的“属性”,依次选择弹出对话框的“主目录-〉配置”将会弹出如图七所示的对话框。
(图七)
在Web Service服务器端程序设计期间,因为需要不停的修改、编译和测试程序运行,所以不能使用“缓存ISAPI应用程序”,否则一旦运行程序,服务器程序就会总是处于使用期间,重新编译的新程序无法覆盖。
而一旦服务器端程序完成以后,则最好选择“缓存ISAPI应用程序”,因为一旦运行ISAPI程序它会被调入缓存以后,在以后的执行中效率会大大提高,据测试,至少有一倍以上的提升幅度。
2、 Delphi 6创建Web Services工程的调试方法:
作为一个运行于IIS下的ISAPI应用程序,Delphi创建的Web Services是一个DLL动态库,所以调试方法和一般的应用程序不太一样:
在创建Web Services程序的向导中,应该选择Web App Debugger excutable程序,创建出来的将会是一个可执行程序。然后使用Delphi 6自带的“Web App Debugger”调试工具作为Web Sever,并设置对应的端口,这时候就可以在Delphi的IDE下面调试服务器程序了。
当程序调试运行正常以后,需要作为ISAPI发布,只需要重新建立一个Web Sercices ISAPI程序,并把调试程序下的相关文件全部加入到新工程就可以了。
三、 总结:
在以上的测试中已经证明了,Web Services能传递各种各样的资料形式,由于Delphi已经为它封装了底层类进行传输复杂类型资料,因此,用Delphi6开发Web Services也比较简单。当前面临的主要问题就在于与Microsoft之间的整合问题,Delphi 6对微软WSDL的解释出现错误,和一些其它的相互之间差异,导致它们之间无法相互调用。虽然可以在Delphi 6中使用MST2进行调用,但是这就等于抛弃了Delphi 6自身的Web Services支持。
在整个测试过程中,我主要注重了Web Services实用性方面的测试,Web Services虽
然在传输效率极稳定性上都还不是特别的理想,但是毕竟微软的.Net战略是一个对现在来说超前的概念,它的真正成熟必须依靠与宽带网络的普及,才能让用户体验到Web Services的优越性。
当前,国内对Web Services的研究才刚刚起步,各大论坛才新近推出相关的讨论版,而且相对比较冷清。作为今后软件技术的核心概念,Web Services的火热程度将会有增无减。
随着各软件厂商参与Web Services研发的积极性,正促使着Web Services的迅速发展,以及相关协议的确定。随着外部环境的日趋成熟和自身的完善,Web Services必然作为全新的软件开发理念席卷整个行业。正如微软所说:“Empower people through great software -- any time, any place and on any device.”(先进的软件让人们随时,随地,通过任何设备获得强大能量)
参考资料:
《肥皂的战争与和平》----- 李维
《.Net:解读微软互联网新战略》-----毛向辉 陈志红
《Borland Delphi 6 Help》
《Borland Delphi 6 for Windows Develper’s Guide》
……