RemObjects文档翻译2.docx
《RemObjects文档翻译2.docx》由会员分享,可在线阅读,更多相关《RemObjects文档翻译2.docx(21页珍藏版)》请在冰豆网上搜索。
RemObjects文档翻译2
R003-RemoteInvocation
RemoteInvocation可以让客户端像调用本地方法一样调用远程服务器上的方法.这个过程叫做RemoteProcedureCall(RPC).
为了实现这个功能,客户端首先就要和一个类似于远程服务器的代理对象接口通讯.
这个代理对象叫做代理(proxy).代理可以将方法调用转换成流在网络中传递.
服务器端接收到这个数据包,欢迎他的信息,调用真正的方法.最后将执行结合或错误信息打包发送到客户端的代理.
最后,代理发送执行结果给调用者.像调用本地方法一样.
RemObjectsSDK3.0简介中我们看到了他的新特性和工具,这些都可以给我们开发方式带来很大的改进.这篇文档我们看看关于产品的概况和令人兴奋的新特性.
ServiceTester用处
分布式系统提供的灵活性和适用性是传统的CS结构无法比拟的.但是开发和测试分布式系统通常复杂费时.在基于服务的客户端程序开发中我们只是调试本程序还是不够的,还有大量的交互式请求和特定的服务过程大量触发的效率等.
一般的测试方案产生出脚本并测试最终用户应用,但不能做到真正的模拟大量用户来代理远程服务器或使用一些RemObjects特性.
这样你可以自己写测试应用程序或使用像DUnit的测试工具,但是还要有很多工作要作.
RemObjects服务测试(ROST)可以解决这些问题.为每个服务方法产生测试脚本并使用多线程并发调用这些方法.测试完成ROST提供测试图解,其他的事物,每秒钟请求数量,网络传输情况等信息.测试脚本可以保存,你修改了远程服务方法后可以再次运行查看修改后对系统效率和功能改善.
ROST支持所有数据类型:
简单数量类型,复杂的结构体,二进制流和数组.通过直观的界面可以输入测试函数的参数并观测最终执行结果.
下面的截图可以看到如何启动ROST来执行MegaDemo中的EchoPerson方法:
下面的截图是测试正在进行时的情况:
ROST经配置后使用RemObjectsSDK提供的所有通道(channels)和消息(message).
下面的截图显示连接配置对话框:
ROST是一个很有价值的好帮手,使用它可以在测试评估你的应用程序服务器时节省大量时间.这完全是RAD操作!
客户端均衡负载和容错处理
RemObjectsSDK的设计目标是成为一个可升级系统.
默认的,RemObjects不指定固定连接,我们不用写代码就可以实现连接单个服务器或多个服务器.在Cisco范例中,Windows网路均衡负载,F5Networkshardware,和其他硬件软件都与RO-based系统无缝的集成在一起.
RemObjects3.0的传输通道已经升级支持客户端的均衡负载和容错.本质上你可以为你的通道的TROServerLocator属性明确的提供一系列的服务器列表.你可以控制通道的均衡负载请求,或在当前服务器故障时选择另外一个.通道可以寻找服务并自动发现在线的服务器,但如果要尝试搜寻所有可能的目的源时很能会报异常.
下面的截图是在TROWinINetHTTPChannel中设置属性:
下面的截图展示了独立的TROServerLocator列表:
最后,这个截图显示测试应用程序的两个服务器通过连接和断开模拟断线条件输出的结果:
COM和Active脚本支持
虽然RemObjects服务器可以连接任何操作系统和客户端(Windows,Linux,PocketPCs,.Net,Mono,和其他用ANSI-C编译的程序),但在Windows系统下,COM几乎成了标准的用法.一些应用程序像Excel,Word,LotusNotes可以通过OLE操纵,有的高级用户可以用VBScript脚本控制它们.在Web开发中,ASP的Web页面经常使用相似及的技术操作COM对象(VBScript或JavaScript).
RemObjects3.0使用COMDLL规则,这样可以使一种语言能使用不同的RemObjects服务器.RemObjectsSDK3.0生成的COMlibrary发布的库如下:
ROServer.CreateService方法用服务方法名作参数返回一个对象可以将COM方法调用转换为RemObjects调用(二进制流或Soap).
通过使用ChannelType和MessageType属性(都是字符串),你可以确定组件的类型,像TROBINMessage和TROWinINetHTTPChannel,与服务器通信.
通过使用SetXXXProperty和ReadXXXProperty方法你可以自定义属性,例如TargetURL或自定义压缩.
下面的截图展示了Excel电子表格调用MegaDemo服务器的Sum方法:
与按钮相关的代码如下:
PrivateSubCommandButton1_Click()
Dimresult
SetROServer=CreateObject("RemObjects.COMServer")
ROServer.MessageType="TROBINMessage"
ROServer.ChannelType="TROWinInetHTTPChannel"
ROServer.SetChannelProperty"TargetURL","http:
//localhost:
8099/BIN"
SetMegaDemoService=ROServer.CreateService("NewService")
DimA,B
A=Sheets("Sheet1").Cells(9,4).Value
B=Sheets("Sheet1").Cells(10,4).Value
result=MegaDemoService.Sum(A,B)
MsgBox"Sum"&A&"+"&B&"="&result
SetMegaDemoService=Nothing
SetROServer=Nothing
EndSub
下面的截图展示了ASP页面向用户显示简单信息:
代码如下:
<%
Dimresult
SetROServer=Server.CreateObject("RemObjects.COMServer")
ROServer.MessageType="TROBINMessage"
ROServer.ChannelType="TROWinInetHTTPChannel"
ROServer.SetChannelProperty"TargetURL","http:
//localhost:
8099/BIN"
SetMegaDemoService=ROServer.CreateService("NewService")
Response.Write"ThisisanASPpagethatinvokesmethods"
Response.Write"oftheRemObjectsMegaDemo
"
result=MegaDemoService.Sum(100,200)
Response.Write"Theresultof100+200is"&result&"
"
result=MegaDemoService.GetServerTime
Response.Write"Thetimeontheserveris"&result
SetMegaDemoService=nothing
SetROServer=nothing
%>
广播服务事件–服务器端
广播服务事件是RemObjects3.0新特性,运行服务器异步执行客户端的回调函数.回调函数是在客户端定义而由服务器相应一个事件时调用.
假设一个聊天程序,当一个用户类型信息被中心服务器接受后,再转发到其他所有的用户.为了发送消息,服务器端需要调用客户端事件句柄(如OnSendMessage方法).只有当服务器能通过客户端的IP与其交互,或客户端在服务器回调中是启动的,才能完整这个功能.
RemObjectsSDK2.0中可以让应用程序的客户端和服务器端同时调用我们描述的回调函数,但是这只限于局域网(由于网路地址转换的问题);
下图是解释:
当客户端1发送一个消息,由于服务器知道客户端2的直接IP地址(192.168.0.101)可以将其发送到客户端2.而客户端3和4是不能到达的,因为使用了共享IP地址(24.100.3.36)与聊天程序服务器相连.事实上不同局域网要共享相同的IP地址增加了其他的复杂性.网络中的设备像网关,防火墙给整个问题带来了更大的复杂性.
通常,写不可升级和多网络碎片的分布式系统回调可以避免.要使你的系统支持升级并让客户端接受远程通知的唯一解决方法就是使用基于客户端轮询和服务器队列的通道.而这就是广播服务器事件提供的.
RemObjects3服务器可以将客户端定时发送的消息存储在队列中,如下图:
当客户端接受一个消息,他们将调用特定的事件处理程序(于Delphi的事件规则相同).
这个基于RemObjects3.0的聊天程序展示了如何生成用户连接一个或多个服务器上的程序.这个例子可以让系统管理员远程断开客户端或适时的向客户端发送系统消息.
下面的截图展示了两个客户聊天的Session,收到了一个服务器要重新启动的消息.
在RemObjects3.0中这种功能很好实现.服务器端我们定义了一个ChatService服务:
IChatService=interface
['{6893042C-3354-4AE6-B5FA-E7A637475C30}']
procedureLogin(constUserID:
String);
procedureLogout;
procedureSendMessage(constMessageText:
String);
end;
下面截图展示ServiceBuilder:
这个例子的目标是当一个方法被调用将在每个客户端抛出特定的事件.在RemObjects3.0中等以事件使用新类型"CallbackSink"[这个名字将在发布版本中改变].
聊天服务程序包含2个callbacksinks例子:
ChatEvents(OnLogin,OnLogout,OnSendMessage)(当其他客户端有操作时客户端接收)和ChatServerEvents(OnSystemShutdown,OnMandatoryClose)(系统管理员向客户端发送消息).
下图展示了如何在ServiceBuilder定义ChatEvents:
RemObjects预处理程序可以自动生成代码和callbacksinks必要的接口声明.这是Delphi声明的ChatEvents和ChatServerEvents:
{IChatEvents}
IChatEvents=interface
['{75F9A466-518A-4B09-9DC4-9272B1EEFD95}']
procedureOnLogin(constaUserID:
String);
procedureOnLogout(constaUserID:
String);
procedureOnSendMessage(constaUserID:
String;
constaMessage:
String);
end;
{IChatServerEvents}
IChatServerEvents=interface
['{E80B0A2E-96ED-4F38-A6AC-E4E0B59F27F3}']
procedureOnSystemShutdown(constShutdownDelay:
Integer;constReason:
String);
procedureOnMandatoryClose(constClientID:
String;
constReason:
String);
end;
下面的代码是执行在CharService中的Login方法,他触发了所有客户端OnLogin事件:
procedureTChatService.Login(constUserID:
String);
begin
{Checksiftheuserisalreadyloggedin}
iffUsers.IndexOf(UserID)>=0
thenraiseException.CreateFmt('User%sisalreadyloggedin',
[UserID]);
{Addstheusertothelistofloggedusers}
fUsers.Add(UserID);
Session.Values['UserID']:
=UserID;
{GeneratestheOnLoginevent}
(EventRepositoryasIChatEvents_Writer).OnLogin(Session.SessionID,
UserID);
end;
最后一行代码(EventRepositoryasIChatEvents_Writer).OnLogin(Session.SessionID,UserID);在所有的客户端触发OnLogin事件.虽然开起来有些零乱,但是这样很简单而且与标准控件事件同样工作.这段代码与TButton.Click方法等效:
procedureTButton.Click;
begin
//...
ifAssigned(OnClick)thenOnClick(Self);
end;
主要的不同是事件1在服务器端触发并有多个接收者(广播),而事件2不是立即执行的,因为实际上OnLogin调用存储后有其它用户触发.
EventRepository属性指向一个拖放到主窗体的存储对象,其中存储了OnLogin,OnSendMessage等序列化方法和其参数.IChatEvent_Writer是在声明ChatEvents时生成的特殊接口,并可以在存储器中初始化IChatEvent消息.代理依赖事件存储器就像标准的RemObjects代理依赖传输端口一样.
TChatEvents_Writer.OnLogin被包含在ChatLibrary_Intf.pas文件:
procedureTChatEvents_Writer.OnLogin(constSender:
TGUID;
constaUserID:
String);
var__eventdata:
Binary;
begin
__eventdata:
=Binary.Create;
try
__Message.Initialize(NIL,'ChatLibrary',
EID_ChatEvents,'OnLogin');
__Message.Write('aUserID',TypeInfo(String),aUserID,[]);
__Message.Finalize;
__Message.WriteToStream(__eventdata);
Repository.StoreEventData(Sender,__eventdata);
except
__eventdata.Free;
end;
end;
就像我们期待的一样,这也是自动生成的.
在服务器方法中,下面的是在客户端向其他客户端发送信息时由此客户端触发的代码:
procedureTChatService.SendMessage(constMessageText:
String);
varthisuserid:
string;
begin
{Extractthenameoftheuserinvokingthismethod
byreadingsessioninformation}
thisuserid:
=VarToStr(Session.Values['UserID']);
{GeneratestheOnSendMessageevent}
(EventRepositoryasIChatEvents_Writer).OnSendMessage(
Session.SessionID,thisuserid,MessageText);
end;
又一次使用了一行代码触发远程事件.
广播服务事件–客户端
写客户端相应服务器事件也很简单.基本上只要实现事件接口(IChatEvents和IChatServerEvents)及通知RemObjects框架对象已经实现了这些接口.
一个新的控件TROEventReceiver在轮询远程事件存储器,周期性的查看服务器是否有未处理的消息并在需要的时候调用对象方法.
客户端包含一个叫做EventReceiver的TROEventReceiver控件.在客户端例程中,主窗体实现了IChatEvents和IChatServerEvents接口,声明如下:
TClientForm=class(TForm,IChatEvents,IChatServerEvents)
//...
protected
{IChatEvents}
procedureOnSendMessage(constaSender,aMessage:
string);
procedureOnLogin(constaUserID:
string);
procedureOnLogout(constaUserID:
string);
{IChatServerEvents}
procedureOnSystemShutdown(constShutdownDelay:
Integer;
constReason:
String);
procedureOnMandatoryClose(constClientID:
String;
constReason:
String);
//...
end;
当用户点击Login按钮,下面的代码将执行:
procedureTClientForm.bbLoginClick(Sender:
TObject);
begin
try
ROChannel.TargetURL:
=cbServer.Text;
{Callstheremoteloginmethod}
fChatService.Login(UserID);
{Registertheeventhandlersusingthe
TROEventReceivercalledEventReceiver}
EventReceiver.RegisterEventHandlers(
[EID_ChatEvents,EID_ChatServerEvents],
[Self,Self]);
{Startspolling}
EventReceiver.Active:
=TRUE;
fLoggedIn:
=TRUE;
finally
ToggleControls;
end;
end;
方法TROEventReceiver.RegisterEventHandlers获取一系列的回调接口ID(parameters[EID_ChatEvents,EID_ChatServerEvents])及实现他的对象(这个例子都是self,因为这里都是用MainForm实现这两种事件处理接口的).
EID_xxx是与回调接口同名的字符串常量,声明如下:
unitChatLibrary_Intf;
//...
const
//...
{EventID's}
EID_ChatEvents='ChatEvents';
EID_ChatServerEvents='ChatServerEvents';
当IChatEvents或IChatServerEvents事件到达,MainForm中相关的方法将自动执行,这就像OnClick事件一样,这些都是对开发者透明的.
下面的一小段程序展示了OnLog,OnSendMessage,OnSystemShutdown的实现,这些方法觉定了在运行期如何输出信息:
procedureTClientForm.OnLogin(constaUserID:
string);
begin
WriteMessage(mtSystem,'','User'
+aUserID
+'justloggedin');
end;
procedureTClientForm.OnSendMessage(constaSender,
aMessage:
string);
begin
WriteMessage(mtMessage,aSender,aMessage);
end;
procedureTClientForm.OnSystemShutdown(constShutdownDelay:
Integer;
constReason:
String);
begin
Beep;
MessageDlg(Format('Theserverwillbeshutdownin%dminutes.'
+#13'Reason:
%s',[ShutdownDelay,Reason]),
mtWarning,[mbOK],0);
end;
WriteMessage是一个向MainForm窗体的Memo控件显示文本信息的简单函数.紧记,除了调用EventReceiver.RegisterEventHandlers和用户注销时的EventReceiver.UnregisterEventHandlers,实现消息处理接口外,不再需要其他的处理事件了.
MasterServer
TheRemObjectsSDK允许我们将Session信息存储在内存中或数据库中,如果你想要你的系统均衡负载和容错,需要将Session保存到每个服务器都可以存取的数据库中,这样客户端无论连接到哪台服务器都可以取出一致的Session信息.这个功能就是RemObjectsSDK2.0的TRODBSessionManager提供的.但是,数据库Session管理折中了速度和需求.
存取远程数据库比使用内存数据要慢,并且要设置存储Session信息必需的表结构.
RemObje