码迷,mamicode.com
首页 > 其他好文 > 详细

RemObjects 客户端完整执行流程

时间:2016-07-04 06:29:24      阅读:162      评论:0      收藏:0      [点我收藏+]

标签:

RemObjects是一个强大的N层网络框架,写一个实现即可通过多种连接方式(http,tcp/ip,webservice...)被不同客户端调用
这里我将通过源代码展示一下客户端的调用过程,因为RO封装得实在太好,程序员根本不需要关心太多细节,只需要根据需求编写实现即可,了解其实现原理,可增强自己的设计思想,现在请一步一步来看下这个过程
技术分享
首先是客户端调用就是这么简单,一个TRORemoteService对象转成服务端的一个接口,即可调用服务端的接口函数,
其实在程序启动的时候就已经完成了大多数工作了,先是看下主窗体的文件引用
技术分享 
当在界面摆上以下3个控件

技术分享
 ROMessage: TROBinMessage; 
 RORemoteService: TRORemoteService;
 ROChannel: TROIndyTCPChannel;
会自动引入上图的文件, 这里的核心文件是 uROClient
先看下其初始化代码
技术分享 
该代码主要是创建了针对 消息类,通
道类,代理类 的管理列表对象 

_MessageClasses := TClassList.Create; 消息类列表
_ProxyClasses := TStringList.Create; 代理类列表
_TransportChannels := TStringList.Create; 通道类列表

技术分享
当我们使用一种消息格式的类时, 这里以BIN格式为例,引用的uROBinMessage文件会在程序启动之初,
将该对象处理类TROBinMessage加入消息类的列表
 技术分享
通道类也一样,这里以TROIndyTCPChannel 为例 

技术分享

技术分享

客户端要调用服务端的接口INewService,需要服务端提供一个接口代理类TNewService_Proxy,
初始化时也是通过注册函数添加到uROClient里的代理类对象,
方式和 消息类,通道类 的过程类似 
技术分享 
技术分享

以上部分就是程序一启动时所做的初始化工作

=============================

回到客户端的代码,一句代码是如何实现整个调用过程的呢?
技术分享
首先RORemoteService是一个接口实现类对象,调用 as 操作时会使用接口查询,看下代码
技术分享 
这里会调用 FindProxyClass 函数到_ProxyClasses 代理类列表对象里搜索我们要调用的服务端接口 INewService 的代理类,
如果找到则返回该代理类对象,因为程序启动时 TNewService_Proxy 已经注册到 _ProxyClassess 里,所以这里实际返回的就是
TNewService_Proxy,返回后再创建实例对象proxy := proxyclass.Create(Self); 
 构造函数的参数是 TRORemoteService 对象自身;(RORemoteService as INewService) 返回的就是代理类的对象,
那么在创建代理类对象又做了些什么呢?
技术分享 TNewService_Proxy 类没有构造函数,所以这里调用的是其父类TROProxy 的构造函数
技术分享
技术分享
因为 RORemoteService 的对象的 Channel,Message属性分别为 ROChannel,ROMessage;
所以代理类对象其实就是把这两个对象给保存起来

返回来代理类对象,接下来是调用接口函数 Sum
技术分享
代理类的__GetMessage属性获取的就是构造函数里传入的TRORemoteService对象的 Message 属性
 技术分享
同理获取通道对象,所以这里的 lMessage 实际上就是窗体的  ROMessage: TROBinMessage; 对象
lTransportChannel 实际上就是窗体的 ROChannel: TROIndyTCPChannel; 对象

接下来的代码开始对入参进行指定消息格式的打包

lMessage.InitializeRequestMessage(lTransportChannel, ‘NewLibrary‘, __InterfaceName, ‘Sum‘);
lMessage.Write(‘A‘, System.TypeInfo(Integer), A, []);
lMessage.Write(‘B‘, System.TypeInfo(Integer), B, []);
lMessage.Finalize;
首先是在请求数据头里写入要调用服务端接口及函数名称,然后再以序列化的方式写入入参数据技术分享
技术分享
技术分享
技术分享
技术分享
技术分享

这里用到的对象序列化思想,简单地说就是把一个对象按一定的格式保存到流对象里,这个过程可以理解为 封包
数据按消息类打包后,调用通道类进行传输
lTransportChannel.Dispatch(lMessage);
技术分享

这里的核心函数 IntDispatch 处理了 
连接:IndyClient.Connect;
发送:IndyClient.IOHandler.Write(lStream, lStream.Size, TRUE);
接收:IndyClient.IOHandler.ReadStream(lStream);
断开:IndyClient.Disconnect;
这里的 IndyClient 是 TIdTCPClient 类对象,
也就是 通道类TROIndyTCPChannel 底层通讯其实就是通过TIdTCPClient 实现的
 
技术分享 
技术分享 
服务端接收到数据后会 解包,然后调用数据头里的接口函数,计算返回的数据再 打包  发送到客户端,
客户端接收到返回的数据后,再 解包,并读取返回结果
lMessage.Read(‘Result‘, System.TypeInfo(Integer), Result, []);

以上这就是整个客户端的调用过程

RemObjects 客户端完整执行流程

标签:

原文地址:http://www.cnblogs.com/erp-system/p/5639266.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!