RealThinClient LinkedObjects Demo解析
作者:不详,搜索自网络,如有侵权,请告知
从成功学得少,从失败学得多这个Demo源码实现斗劲怪,有点拗脑,原因估是作者想把控件的应用做得简单,而封装太多。
恋情是友情的精华,手札是恋情的妙药这里说是解析,其实是粗析,俺没有耐烦每个实现点都查实清楚,看源码一般也就连读带猜的。
这个Demo表达出的意义,在于在HTTP接见体式格式下,很便利的实现了客户端和办事端彼此的主动通信才能,这在须要及时消息交互,把握交互,数据互传上很是有意义,很是给力。
一、Demo工作过程
1. 实现功能:实现了上传文件到HTTP办事端的才能,大文件上传成功率极高,并且始终对峙很是少的内存占用量。
2. 工作过程:客户端和办事端的TRtcLinkedModule控件需建树通信连接,在Demo中有两种体式格式,客户端先创建TRtcLinkedModule对象和办事端先创建TRtcLinkedModule对象,但无论哪一端先创建,都邑激发对端也创建对象,从而使两对象的通信连接建树。完成建树后,办事端把文件存储路径推送给客户端,客户端选择文件后,调用办事端Upload处理惩罚流程(这儿只能说是处理惩罚流程,而不是函数,因为TRtcLinkedModule对象的长途调用老是只触发对端的OnCallMethod事务,经由过程在Param中应用字符串标识,如“Upload”告诉办事端应用哪一个处理惩罚流程)开端上传,办事端在Upload中先断定是否文件已存在,不存在的话,直接调用客户端的“Get”流程让其上传数据,且每次“Get”调用只请求客户端发送10K数据,客户端筹办好数据后调用办事端的“Put”把数据送到办事端并写入文件,“Put”过程又再调用“Get”,如此来去,直至完成全部数据上传。
二、实现道理和关键函数
1. TRtcLinkedModule控件
(1)此控件可放置在Form、DataModule、Frame这类容器上,一个容器只能有一个该控件!放置了该控件的模块即成为通信模块,可以在通信须要时由远端创议实例创建恳求而创建(除了放控件外,当然还有几行代码的工作要做,下面讲述)。
(2)控件的字符串属性RemoteClass设置为远端的模块名字,如许当要远端创建Link模块进行通信时,RTC会把此名字作为标识发送创建恳求到远端,远端则按照名字创建正确的模块。
(3)成员函数CallMethod(const xMethodName: string)直接触发对端的OnCallMethod事务,事务中按照xMethodName断定处理惩罚体式格式,看起来一般用于数据块或错杂把握上。
(4)成员函数SetProp(const xPropName: string; xNow: boolean)、SetEvent(const xEventName: string)直接触发对端的OnSetProp和OnSetEvent事务,用于简单的短消息交互或把握交互。
(5)成员函数Broadcast(const xChannel, xMethodName: string)在本地模块内群播消息,xChannel为群播管道,管道由成员函数Subscribe(const xChannel: String)建树。
(6)控件应用相当简单,以上属性设置后就完成,不消管如何和http通信控件啊或ClientModule等远调控件进行连接,扔上就可用了(这也是让人斗劲困惑的处所,后面有解析它是如何和http通信控件接洽关系的)。
2. 函数RegisterRtcObjectConstructor(const xClassName:String; xProc:TRtcObjectConstructor):
(1)必须在initialization块履行,必须和UnregisterRtcObjectConstructor配对应用
(2)这个函数用于指定一个能被远端调用的机关函数,用于能让远端在须要时创建TRtcLinkedModule对象及模块
(3)函数的xClassName在TRtcLinkedModule控件中的RemoteClass中指定,xProc为一个procedure MakeObject(Sender:TObject; Param:TRtcObjectCall);类型的静态函数,这个函数就是为什么在须要时就能创建远端Link模块的关键了,发明需求到来时,按照RegisterRtcObjectConstructor函数的注册信息,找到xProc函数调用,OK,Link模块对象生成了,道理很简单吧。
(4)另一个调换规划为可以在TRtcClientModule或TRtcServerModule控件中的OnObjectCreate事务中进行创建工作,但这须要两端应用此Module控件进行通信。
函数意义:远端发送创建LinkObject通迅对象号令,本地端按照远端发来的xClassName字串在ObjectManager中找到注册的指定机关函数并调用。所以法度须要应用ActivateObjectManager创建好对象经管器。
3. 函数ActivateObjectManager(xCreate:boolean=True),TRtcDataServer和TRtcClientModule成员函数。
(1)在应用TRtcLinkedModule控件进行通信前必须调用该函数,不然不克不及和远端通信,也不克不及正常创议远端模块创建恳求。
(2)RtcClientModule1.ObjectLinks为“ol_Manual”必须手动调用,设置为“ol_AutoClient”或“ol_AutoBoth”则RTC会在后台主动调用。
不由得插句对于长途函数调用架构的一点见地:
RemObject套件用的是看起来很合适常规懂得的函数调用,让你感触感染不到这是长途函数,为实现如许一个应用感触感染,RO用了斗劲错杂的技巧来实现,不成否定,如许相当有含金量,不是谁都可以写得出来的,这种技巧曾如此让我赞服并进修。而RTC的长途调用全部用字符串标识体式格式,如此的简单,实现起来不须要错杂的技巧,大多有点经验的法度员基于TCP之类底层都可以做出来,而但多年后的如今,我才发明这种简单的美和高效,字符串可以描述从简单到极其错杂的机关,网页啊,xml啊这不都是如许描述的么,因而其灵活度可以说没有羁绊,要实现什么能实现什么如何实现只在乎用者同心专心。RTC的作者在编程思惟境界上必然已是十分的修为深厚了。
三、新鲜的处所
按事理,TRtcLinkedModule控件要能进行通信,必然要有设置通信体式格式的处所,但找完TRtcLinkedModule的属性和Demo的源码,都没有发明有设置的处所,那它是怎么完成通信的呢?
先看看TRtcLinkedModule的机关函数里都干了什么:
1 constructor TRtcLinkedModule.Create(AOwner: TComponent);
2 begin
3 inherited Create(AOwner);
4 if not (csDesigning in ComponentState) then
5 begin
6 // This will only work if there is an active Object Manager for the current thread
7 FParam:=TRtcObjectCall.Create(GetRtcObjectManager);
8 if assigned(AOwner) then
9 FOLink:=TRtcBasicObjectLink.Create(AOwner,FParam.Manager)
10 else // If no Owner, we are the Object container
11 FOLink:=TRtcBasicObjectLink.Create(self,FParam.Manager);
看到了GetRtcObjectManager,这是个全局函数,按照线程ID获取对象经管器,ObjectManager估计是个全局的、独一的单例模式的对象,懒得看代码了,猜的,哈哈。
ObjectManager估计是个LinkObject的经管器,用于Link控件发送的恳求到来时找到正确的模块及正确的Link控件,然后调用对应的函数,如今的疑问是,ObjectManager怎么知道把恳求发送到对应的Form和Link去呢?上方代码中FOLink:=TRtcBasicObjectLink.Create(AOwner,FParam.Manager),看到传入AOwner了!还有Manager,干啥呢?持续跟下去看看TRtcObjectLink.Create是什么:
1 constructor TRtcObjectLink.Create(xOwner:TObject;xManager:TRtcObjectManager);
2 begin
3 inherited Create;
4 if xOwner=nil then
5 raise ERtcObjectLinks.Create(""TRtcObjectLink.Create called with xOwner=nil"");
6 if xManager=nil then
7 raise ERtcObjectLinks.Create(""TRtcObjectLink.Create called with xManager=nil"");
8 FSubs:=nil;
9 FOwner:=xOwner;
10 FManager:=xManager;
11 if FManager.CreatingObjectID<>0 then // remote constructor
12 begin
13 FOID:=FManager.CreatingObjectID;
14 FManager.CreatingObjectID:=0;
15 FCreator:=False;
16 end
17 else
18 begin
19 FOID:=FManager.GetNextObjectID;
20 FCreator:=True;
21 end;
22 FRemoteDestroyed:=False;
23 FManager.AddObject(FOID,self,FOwner);
24 end;
最后一句:FManager.AddObject(FOID,self,FOwner);很明显了,这儿TRtcObjectLink的对象标识FOID和自身对象指针Self及地点的窗口FOwner被传入,三个的对应关系都有了,ObjectManager要找到正确的模块那是很轻易的事。而TRtcObjectLink对象内嵌于TRtcLinkedModule控件对象中,是组合关系,具体函数和事务调用是TRtcObjectLink的实现。
如今还有个题目是,Link对象是怎么获得通信才能的?
重视到,RtcClientModule1.ActivateObjectManager(True);这个调用,RtcClientModule1是连接到TRtcHttpClient对象的,是以具备http通信才能,再看看RtcClientModule1和ObjectManager是什么关系:
1 procedure TRtcClientModule.ActivateObjectManager(xCreate:boolean=True);
2 begin
3 if FRelease then Exit;
4
5 if ObjectLinks=ol_None then
6 raise ERtcObjectLinks.Create(""ActivateObjectManager: ObjectLinks = ol_None"")
7 else if not assigned(FObjectManager) then
8 if xCreate then
9 begin
10 FObjectManager:=TRtcClientObjectManager.Create(False);
11 FObjectManager.BroadcastGroup:=String(FObjManSesName);
12 FObjectManager.OnDataReady:=DoObjectManagerDataReady;
13 end;
14
15 if not assigned(FObjectManager) then
16 raise ERtcObjectLinks.Create(""ActivateObjectManager failed"")
17 else
18 begin
19 SetRtcObjectManager(FObjectManager);
20 FObjectManager.uteBroadcast(nil);
21 end;
22 end;
噢,本来这家伙发明没有ObjectManager的话就创建一个并持有,并且用SetRtcObjectManager送到一个全局对象fObjManagers中,这个对象是个列表,而GetRtcObjectManager恰是从这个fObjManagers中获取,如今本相大白了,本来就是TRtcHttpClient控件收到恳求转给TRtcClientModule对象,TRtcClientModule对象的私有成员FObjectManager保存着ObjectManager的对象引用,ObjectManager对象按照保存的Owner、Link对象关系找到正确的模块,调用Link对象相干函数。嗯,不过具体代码没有细看,以上本相有较大猜测成份,不过我信赖事理上应对的,本质性实现上,请看到这篇文章的有心网友指出,批驳斧正,共同进步。MRMY