RemObjects 客户端完整执行流程

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, []);

以上这就是整个客户端的调用过程
原文地址:https://www.cnblogs.com/erp-system/p/5639266.html