程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> RemObjects 客戶端完整執行流程,remobjects流程

RemObjects 客戶端完整執行流程,remobjects流程

編輯:Delphi

RemObjects 客戶端完整執行流程,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, []);

以上這就是整個客戶端的調用過程

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved