PowerBuilder创建分布式程序
17.1 创建分布式程序上几章中,我们介绍了PowerBuilder分布式计算的基本概念,在接下来的章节中,我们将做一个简单的分布式程序。我们来看一下一个已经存在的应用程序,然后将做成的分布式运行的程序。
[img]http://www.lukin.cn/up_files/image/2006-2-20/46802531.gif[/img]
图17-1
单击Library按钮,打开一个名为Clients的库,单击Clients应用对象。按Run按钮(图17-1)。
这是一个商品预定程序,所预定的是个人电脑配件。这是一些电脑常用配件名,旁边所列的配件的价格,这些价格来自电脑分销商的远程数据库。分销商将定期更改这些数据库中的价格表。最后的分销商给购买者折扣。与电脑配件不同的是,折扣值的是不公开的,分销商将给予不同的购买用户以不同的折扣,折扣的计算方法是秘密的,并且不断变化。
因此,我们想把电脑预定程序做成一个分布式运行的程序,让计算折扣的程序运行在我们的服务器中,这样做的目的一方面是保密,另一方面,在分销商更改折扣算法时,只需更服务端程序,而不用更改在客户端中的电脑预定程序。
.2 Nonvisual Object 与 Proxy Object
第一步,我们所做的是将折扣计算模块生成一个非可视对象NVO。
单击用户对象按钮,按NEW,然后选择Class框中的Custom按钮,系统出现一个用户对象窗口。我们可以注意到窗口的标题栏中有一句话为:Inherited from Nonvisual Object,它说明我们所创建的对象正是NVO。接着我们为NVO定义一个函数。打开Declare菜单中User Object Functions,按NEW按钮,这样就打开了函数定义窗口(图17-2)。这个函数名为GetDiscount,它需要有一个参数为Custom Name(用户名),类型为。字符串型。
[img]http://www.lukin.cn/up_files/image/2006-2-20/46802911.gif[/img]
图17-2
这就是我们的折扣函数。假若用户名为Mohair,则我们给予九折,否则,给九五折。实际函数可能不会这么简单,这里只是一个例子。关闭函数定义窗口,存盘。把这个 NVO 对象取名为 Cnvo_discount 。
下面我们来生成非可视对象Cnvo_discount的代理对象。在用户对象画板上按右键,选中弹出式菜单的set proxy name,取名为Cpo_discount(图16-3)。在File菜单中选择Save,这样就生成了一个为名为Cpo_discount的代理对象。我们可以在Library画板检查一下,PowerBuilder是否真地生成了这个对象。注意,我们是在篇File菜单中选择Save后生成了这个对象的,如果不将之保存,那么,我们只是为这个NVO设置了一个属性,并未生成代理对象。现在,我们已有了两类对象,一个是非可视对象Cnvo_discount,它是折扣计算程序的真正实现的地方,一个完整的对象。另一个是名为Cpo_discount的代理对象,它定义了前者的接口。我们试用鼠标的右键,来编辑这个对象,可以发现,系统并不允许进行编辑,因为它并不是一真实的对象。
[url=http://www.lukin.cn/up_files/image/2006-2-20/46802912.gif][img]http://www.lukin.cn/up_files/image/2006-2-20/46802912.gif[/img][/url]
图17-3
17.3 创建 Connection Object
现在,我们已经定义了NVO,并生成它的代理对象,下一步再来看一看如何定义和初始化它一个链接对象Connection Object。与Transaction对象不一样,系统并不为应用程序自动生成这个对象,而需要自已手工定义。
打开应用程序画板,选择它的Open事件。在其中只有一句打开窗口语句:Open Win_shoping。我们定义一个全程变量,输入:Connection myconnection。再从脚本编辑器中输入myconnect = create connection,为这个connection对象进行初始化。接着我们赋予它三个最基本的属性值:application、driver和location.。在不清楚之前,我们先给它们空值。至此为止,已经为connection对象初始完毕,我们还需用它来服务器建立联系。输入myconnect ConnectToServer。为了检查它是否真地找到了服务器,我们还需要输入一些脚本来验证它的返回值。如它的返回值不为空,则程序提示一些出错信息。如果等于0,则说明它已经正确链接到服务器,于是进一步打开主窗口win_shoping(图17-4)。
我们建立了myconnect对象,相应地,还应该在程序结束之前将它释放掉,以便系统回收这个对象所占的内存空间。打开Close事件,先中止服务端的服务线程,同时释放服务器为我们分配的内存空间。输入myconnect DisconnectServer。随后,再释放myconnect对象,输入destroy myconnect。在PowerBuilder中,如果创建一个用户自定义的对象,我们就在不需要时把它释放掉。
[url=http://www.lukin.cn/up_files/image/2006-2-20/46803561.gif][img]http://www.lukin.cn/up_files/image/2006-2-20/46803561.gif[/img][/url]
图17-4
接下去,我们把这个代理对象加到应用程序中。打开窗口win_shoping,在“折扣”按钮中加入代码。Cpo_discount po_discount:定义一个NVO对象实例;po_discount SetConnect myconnect:这一句,我们为代理指定链接对象;这样每当代理对象调用了一函数,myconnect对象就为应用程序重定向到远程的NVO中,这个NVO存在于服务器中。po_discount = create Cpo_discount:初始化这个NVO实例;最后,我们释放这个实例。
现在,我们已经把程序改成了一个在分布式环境下运行的应用程序。在客户端中,所有函数都指向了这个po_discount代理对象。
在测试这个程序之前,我们对myconnect对象属性作一些修改。再打开Application画板,我们把myconnect的driver属性改为local,并让其它两个属性继续为空。当driver的值为local,PowerBuilder就会把分布式程序当作非分布式程序来运行。当程序调用代理对象,代理转向Connection对象,如果Connection对象发现driver为local,Connection就不会发链接请求信息。我们来测试一下这个程序。按下运行按钮,程序被正确运行了。单击“Discount”,程序返回了“0.9”。
17.4 把 NVO 移到Server中
至此为止,这只是一个单机程序,还没有分布式运行。接一去我们将要NVO移到另外一个PB库中,形成服务端运行的程序。
单击New按钮,系统弹出一个对话框,输入一个新的库名Server,再为Server生成一个新的应用名,名字也为Server,我们不需要系统自动生成的框架。接着,我们想把Clients库中的Cnvo_discount移至Server库中。打开Library画板,单击Clients点PBL,选择NVO对象Cnvo_discount,单击右键,选择Move。再查看Server库,可以发现在Server库中,原来在Clients中的Cnvo_discount已经移到了Server中(图17-5)。
[url=http://www.lukin.cn/up_files/image/2006-2-20/46804001.gif][img]http://www.lukin.cn/up_files/image/2006-2-20/46804001.gif[/img][/url]
图17-5
下一步,与客户端程序相类似,我们为服务端程序定义、初始化Transport对象。单击Server Application,打开脚本,打开Declare中的全程变量定义框。输入transport mytrans,创立一个名为mytrans的transport对象,关闭全程变量定义框。在脚本编辑器中,mytrans = create transport,初始化这个对象。然后,与Connection对象一样,我们还需要mytrans对象设置两个基本属性:应用名Application,驱动程序名Driver。我们暂时把它们设为空(图17-6)。
随后,找开应用对象的Close事件,输入destroy mytrans,以便系统回收mytrans对象分配的资源。关闭脚本编辑器。
17.5 创建Server 界面
至此,我们已经创建了Server库,把Clients库中NVO对象移至Server库中,定义并初始化了Transport对象,接下去需要定义一个运行Server的界面。在钮按栏中按下窗口画板按钮,选择新建。
我们将把这个窗口作为运行Server的主窗口,首先在窗口中移中两个按钮,一个,用来启动服务器的服务进程,取名为“Start ” ,另一个按钮用来中止服务进程,取名为“Shutdown”。
[url=http://www.lukin.cn/up_files/image/2006-2-20/46804411.gif][img]http://www.lukin.cn/up_files/image/2006-2-20/46804411.gif[/img][/url]
图17-6
为了程序更加可视一些,我们再定义一个画面,用来标志服务是否正常启动。移入一个Picture控件,点取右键,选择编辑属性命令Property,系统弹出对象属性对话框。在File Name中点取Browse,选入Stop点BMP,OK。当这个画面中的绿灯亮起来时,就认为服务器已经正确启动了,如果画面中是红灯时,则服务被中止了。
调整一下窗口中控件的位置,然后定义这个窗口的属性。我们把这个窗口名定义为“Discount Computing Server”。接下去,我们来为这两个按钮加上一些适当的脚本,让服务端程序正确运行起来。打开Start按钮的Clicked事件。在Start按扭被按下时,我们应该让Transport对象侦听来自客户机中Connection对象的消息。输入脚本mytrans listen。为了检测是否真地收到了一个正确的Connection对象,我们还需要检查一下对象的返回值。如果返回值不等0,则说明程序得到了一个错误的返回值,服务器没有正确地启动,需要提示一些出错信息。如果不是,则加载显示绿灯的图片,表明已经正确启动。
我们选择这些代码,按下Control C键,将之COPY粘贴板上。选择Shutdown按钮,按下右键,再选择Script,把刚才复制到粘贴板上的代码Copy到这个按钮中。当Shutdown被按下时,我们需要Stop Listening,关掉服务进程。同样,还需要把所显示的图片更改为“红灯亮”。保存所写的脚本,离开窗口画板,保存窗口,把它取名为win_server。
继续回到应用对象,再看一下应用对象的脚本。打开脚本编辑器,选择Open事件。我们在这里初始化了一个名为mytrans的tranport对象,并为它设置了一些基本属性。接下去,为在两台机器上来测试这两个程序作一些准备工作。
打开Application画板,选取Server应用对象,再打开Open事件所对应的代码。在上几节中,定义了一个Tranport对象,但是并未给它赋值。现在,我们将给予它一些适当的属性值。Driver指的是应用程序进行网络通信所用的网络协议。它可以为NamedPipes、或者是WinSock。在Win95或NT中,我们一般选择WinSock,它所对应用低层网络协议为TCP/IP。Application指的是服务器应用名,TCP/IP中,它对应的是一个服务进程的端口号,是一个整型的数值。如,Telnet服务端口号为23,FTP服务端口号为21。为了不与系统服务进程发生冲突,我们可以选择大于4096的任何一个数值。在这里,我们先将它设为5555,然后保存所作的修改。
程序员在编写一些网络环境下的程序时,往往首先在单机的环境下来测试程序。我们将在同一台机器中同时运行Clients和Server。
[url=http://www.lukin.cn/up_files/image/2006-2-20/46804412.gif][img]http://www.lukin.cn/up_files/image/2006-2-20/46804412.gif[/img][/url]
图17-7
在成功生成EXE后,关闭项目对话框,给它取名为Server。
现在转到资源管理器中,来查看一下Server点EXE。找到了它之后,双击,启动服务端程序。在你生成EXE的时候,可能会遇到一些错误提示,系统告诉你找不到一些必要的DLL文件,有三个方法来解决这个问题,可以把位于 [b]Common Files [/b]目录下的Powersoft Shared目录中的所有以DLL结尾的文件都复制到生成EXE文件所在目录;你可以在找到在PowerBuilder系统目录下一个名为PATHGEN的文件,为EXE文件设置路径;第三个方法是为你的应用程序做安装程序。
关闭Server。接下来,我们来修改客户应用程序,让它可以和Server链接。打开Library窗口,选择Clients库,双击Clients。重新回到应用对象的Open事件中,看看那里所写的脚本。在这里,程序初始化了Connection对象,我们还需要给它的三个属性赋于适当的值,让它可以与Server会话。我们把Application属性设为“5555”,这是一个TCP/IP的端口号,它必须与我们在服务端程序所设的端号一致,以便客户端程序能找到在服务器中运行的服务进程。把Driver属性设为“WinSock”,说明应用将用TCP/IP协议进行通信。
最后把服务端程序Location设为LocalHost(本机),当客户应用程序发现Location为LocalHost,它就在本机里寻找服务端程序,而不是在网络中。
[url=http://www.lukin.cn/up_files/image/2006-2-20/46804413.gif][img]http://www.lukin.cn/up_files/image/2006-2-20/46804413.gif[/img][/url]
图17-8
关闭脚本编辑器,选择保存(图17-8)。
我们测试一下这个程序,按下“Discount”,程序正确返回了“0.9”。再来看一看如果关闭服务会发生什么事情。在Server中按下“ShutDown”,再击“Discount”,Clients程序返回错误信息。
至此为止,我们已经看到分布式PowerBuilder在单机环境的运行。在下一节中,我们将把这个应用程序分为两部分,一个运行在客户机中,一个运行在服务器中,实现真正的分布式计算。
17.6 实现分布式计算
在这一编的最后一节中,我们将网络环境中实现PowerBuilder的分布式计算。在我们的程序测试室中,有两台机器,它们都运行Win95。一台作为客户机,一台作为服务器。如果条件允许,推荐用一台性能较好的运行NT的机器作为服务器,这样会运行地更好些。
打开资源管理器,它已经编译成功的Server点EXE复制到一台名为Mohair的机器中,并在那里将运行起来。它是我们的服务器。接下来,我们还需更改一下客户端程序。在Library画板中打开Clients应用,然后点击事件编辑按钮。在上一节的单机测试中,我们暂时把Connection对象myconnect的网络机器位置Location设置为本机Local Host,现在把它设为真正的网络机器名Mohair。保存对它所作的修改。
运行这个程序,按下“Discount”,程序正确返回值0.9。再在那一台名为Mohair的机器中,Shutdown服务进程,再按一下“Discount”,系统报告网络链路错误信息。
在实际运行中,您可能不会这样顺利,测试一个涉及网络通讯的程序相对要困难地一些。在这里面,您可以按以下步骤排除错误:第一,检查网络的物理链路是否真地通了,可以用“网络邻居”测试一下;接下来,检查是否安装了TCP/IP协议,如果您使用的是WinSock,这个协议是必须的;然后,检查网络一些的属性值,比如,在某些环境下,系统要求机器具有一个固定的IP地址,动态分配可能无效的。网络登录方式也可能会影响程序运行的结果 。
页:
[1]