热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

[置顶]根据RemObject的远程方法调用原理实现的简单远程方法调用

根据RemObject的远程方法调用原理实现的简单远程方法调用作者:俞伟QQ:1830

                     根据RemObject的远程方法调用原理实现的简单远程方法调用

                              作者:俞伟      QQ:183088201     邮件:yu924@hotmail.com

 

以下是根据RemObject的远程方法调用原理实现的简单远程方法调用的内容及代码:

因为在RemObject中,调用远程方法需要三个单元,即:XXX_Intf,XXX_Invk,XXX_Impl

(1)XXX_Intf主要是服务接口声明和代理类定义及实现。

(2)XXX_Invk主要是实现了具体的方法执行

(3)XXX_Impl主要是服务接口的具体实现

因为本人比较懒惰,没有像RemObject那样分的那么具体。本文主要讲述远程方法调用的简单实现,让大家可以看出调用的原理,而且实现的代码简单,大家可以通过阅读代码就可以看出相关的原理。

以下是具体的代码:

客户端通过代理类调用

procedure TForm1.Button1Click(Sender: TObject);
var
  iA, iB, iC: Integer;
  obj: TMathFunc_Proxy; //代理类
begin
  iA := StrToInt(Edit1.Text);
  iB := StrToInt(Edit2.Text);
  obj := TMathFunc_Proxy.Create;
  try
    iC := obj.Sum(iA, iB);
  finally
    FreeAndNil(obj);
  end;
  Edit3.Text := IntToStr(iC);
end;

代理类负责构造传递和接收处理与远程服务的交互信息:

function TMathFunc_Proxy.Sum(const A, B: Integer): Integer;
var
  strModuleName,
  strInterfaceName,
  strMethodName: string;
  DNAMessage: TDNAMessage;
begin
  //创建消息交互对象
  DNAMessage := TDNAMessage.Create;
  try
    //创建新的方法调用消息
    DNAMessage.CreateMessage('Test', 'MathFunc', 'Sum');
    //往消息中写入参数值
    DNAMessage.Write('A', TypeInfo(Integer), A);
    DNAMessage.Write('B', TypeInfo(Integer), B);
    //分发传递消息
    DNAMessage.Distributed(DNAMessage.MessageStream);
    //从方法请求结果消息返回的消息中提取相关结果
    DNAMessage.Read('', TypeInfo(string), strModuleName);
    DNAMessage.Read('', TypeInfo(string), strInterfaceName);
    DNAMessage.Read('', TypeInfo(string), strMethodName);
    DNAMessage.Read('Result', TypeInfo(Integer), Result);
  finally
    //销毁方法调用消息
    if Assigned(DNAMessage.MessageStream) then
      DNAMessage.DestroyMessage;
    //销毁消息交互对象
    FreeAndNil(DNAMessage);
  end;  
end;

TDNAMessage类负责消息的序列化和反序列化过程,不过本文中因为没有具体的去实现TCP等协议的通信管道,所以直接在TDNAMessage类的方法Distributed中模拟了整个调用过程中的客户端发送 -> 服务端接收、处理、返回 -> 客户端接收、处理的过程

方法原型:
    procedure Distributed(aStream: TStream);

代码:

procedure TDNAMessage.Distributed(aStream: TStream);
var
  strModuleName,
  strInterfaceName,
  strMethodName: string;
  iA, iB, iC: Integer;
  obj: TMathFunc;
begin
  //在这里我们可以写把方法请求交互消息传递给远程服务
  { TODO -omichelsn -c :  2007-10-11 8:45:24 }

  //此处代码模拟远程服务在接收到客户端发送的方法请求交互消息及相应处理过程
  //-------------------------------------------------------------Begin
  aStream.Position := 0;
  //读取要调用的模块/接口/方法名称等信息
  Read('', TypeInfo(string), strModuleName);
  Read('', TypeInfo(string), strInterfaceName);
  Read('', TypeInfo(string), strMethodName);
  //读取要调用的方法的参数信息
  Read('A', TypeInfo(Integer), iA);
  Read('B', TypeInfo(Integer), iB);
  //调用具体的方法来计算
  obj := TMathFunc.Create;
  try
    iC := obj.Sum(iA, iB);
  finally
    FreeAndNil(obj);
  end;
  //创建法请求交互结果消息
  CreateMessage(strModuleName, strInterfaceName, strMethodName);
  //写入方法调用的结果值
  Write('Result', TypeInfo(Integer), iC);
  aStream.Position := 0;
  //------------------------------------------------------------End
  //在这里我们可以写把方法请求交互结果消息传递给客户端服务
  { TODO -omichelsn -c :  2007-10-11 8:45:16 }

  //在这里我们可以写客户端接收远程服务发送的方法请求交互结果消息
  { TODO -omichelsn -c :  2007-10-11 8:46:48 }
 
end;

以下是全部的源代码:

Unit1单元(客户端调用单元)

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, TypInfo, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Edit1: TEdit;
    Edit2: TEdit;
    Edit3: TEdit;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

uses
  Unit2;
{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  iA, iB, iC: Integer;
  obj: TMathFunc_Proxy;
begin
  iA := StrToInt(Edit1.Text);
  iB := StrToInt(Edit2.Text);
  obj := TMathFunc_Proxy.Create;
  try
    iC := obj.Sum(iA, iB);
  finally
    FreeAndNil(obj);
  end;
  Edit3.Text := IntToStr(iC);
end;

end.

Unit2单元(类似RemObject中的XXX_Intf,XXX_Impl)

unit Unit2;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes;

type
  //MathFunc接口
  IMathFunc = interface(IUnKnown)
  ['{30A624D5-4DA0-43FF-B210-5D5BCAFC5593}']
    function Sum(const A, B: Integer): Integer; stdcall;
  end;

  //MathFunc实现类
  TMathFunc = class(TInterfacedObject, IMathFunc)
  public
    function Sum(const A, B: Integer): Integer; stdcall;
  end;

  //MathFunc代理类
  TMathFunc_Proxy = class(TInterfacedObject, IMathFunc)
  public
    function Sum(const A, B: Integer): Integer; stdcall;
  end;

implementation

uses
  Unit3;
{ TMathFunc }

function TMathFunc.Sum(const A, B: Integer): Integer;
begin
  Result := A + B;
end;

{ TMathFunc_Proxy }

function TMathFunc_Proxy.Sum(const A, B: Integer): Integer;
var
  strModuleName,
  strInterfaceName,
  strMethodName: string;
  DNAMessage: TDNAMessage;
begin
  //创建消息交互对象
  DNAMessage := TDNAMessage.Create;
  try
    //创建新的方法调用消息
    DNAMessage.CreateMessage('Test', 'MathFunc', 'Sum');
    //往消息中写入参数值
    DNAMessage.Write('A', TypeInfo(Integer), A);
    DNAMessage.Write('B', TypeInfo(Integer), B);
    //分发传递消息
    DNAMessage.Distributed(DNAMessage.MessageStream);
    //从方法请求结果消息返回的消息中提取相关结果
    DNAMessage.Read('', TypeInfo(string), strModuleName);
    DNAMessage.Read('', TypeInfo(string), strInterfaceName);
    DNAMessage.Read('', TypeInfo(string), strMethodName);
    DNAMessage.Read('Result', TypeInfo(Integer), Result);
  finally
    //销毁方法调用消息
    if Assigned(DNAMessage.MessageStream) then
      DNAMessage.DestroyMessage;
    //销毁消息交互对象
    FreeAndNil(DNAMessage);
  end;  
end;

end.

Unti3单元(本单元实现了消息创建、序列化和发送返回的过程,类似RemObject中的TROMessage, TROStreamSerializer,和TROSerializer等类的对消息创建、序列化、发送返回的实现过程)

unit Unit3;

interface

uses
  SysUtils, Classes, TypInfo;

type
  IDNAMessage = interface(IUnKnown)
    //读-写整型参数值
    procedure ReadInteger(aName: string; anOrdType : TOrdType; var Ptr);
    procedure WriteInteger(aName: string; anOrdType : TOrdType; const Ptr);
    //读-写字符串型参数值
    procedure ReadString(aName: string; anOrdType : TOrdType; var Ptr);
    procedure WriteString(aName: string; anOrdType : TOrdType; const Ptr);
    //读写参数值入口方法
    procedure Write(aName: string; aType : PTypeInfo; const Ptr);
    procedure Read(aName: string; aType : PTypeInfo; var Ptr);
  end;

  TDNAMessage = class(TInterfacedPersistent, IDNAMessage)
  private
    fStream: TStream;
    procedure ReadInteger(aName: string; anOrdType : TOrdType; var Ptr);
    procedure WriteInteger(aName: string; anOrdType : TOrdType; const Ptr);
    procedure ReadString(aName: string; anOrdType : TOrdType; var Ptr);
    procedure WriteString(aName: string; anOrdType : TOrdType; const Ptr);
  public
    //创建新的方法调用消息
    procedure CreateMessage(aModuleName, aInterfaceName, aMethodName: string);
    //销毁方法调用消息
    procedure DestroyMessage;

    procedure Write(aName: string; aType : PTypeInfo; const Ptr);
    procedure Read(aName: string; aType : PTypeInfo; var Ptr);
    //分发传递消息
    procedure Distributed(aStream: TStream);
    //具体的交互消息
    property MessageStream: TStream read fStream default nil;
  end;

implementation

uses Unit2;
{ TDNAMessage }

procedure TDNAMessage.CreateMessage(aModuleName, aInterfaceName,
  aMethodName: string);
begin
  if Assigned(fStream) then
    FreeAndNil(fStream);
  fStream := TMemoryStream.Create;
  fStream.Position := 0;
  Write('', TypeInfo(string), aModuleName);
  Write('', TypeInfo(string), aInterfaceName);
  Write('', TypeInfo(string), aMethodName);
end;

procedure TDNAMessage.DestroyMessage;
begin
  if Assigned(fStream) then
    FreeAndNil(fStream);
end;

procedure TDNAMessage.Distributed(aStream: TStream);
var
  strModuleName,
  strInterfaceName,
  strMethodName: string;
  iA, iB, iC: Integer;
  obj: TMathFunc;
begin
  //在这里我们可以写把方法请求交互消息传递给远程服务
  { TODO -omichelsn -c :  2007-10-11 8:45:24 }

  //此处代码模拟远程服务在接收到客户端发送的方法请求交互消息及相应处理过程
  //-------------------------------------------------------------Begin
  aStream.Position := 0;
  //读取要调用的模块/接口/方法名称等信息
  Read('', TypeInfo(string), strModuleName);
  Read('', TypeInfo(string), strInterfaceName);
  Read('', TypeInfo(string), strMethodName);
  //读取要调用的方法的参数信息
  Read('A', TypeInfo(Integer), iA);
  Read('B', TypeInfo(Integer), iB);
  //调用具体的方法来计算
  obj := TMathFunc.Create;
  try
    iC := obj.Sum(iA, iB);
  finally
    FreeAndNil(obj);
  end;
  //创建法请求交互结果消息
  CreateMessage(strModuleName, strInterfaceName, strMethodName);
  //写入方法调用的结果值
  Write('Result', TypeInfo(Integer), iC);
  aStream.Position := 0;
  //------------------------------------------------------------End
  //在这里我们可以写把方法请求交互结果消息传递给客户端服务
  { TODO -omichelsn -c :  2007-10-11 8:45:16 }

  //在这里我们可以写客户端接收远程服务发送的方法请求交互结果消息
  { TODO -omichelsn -c :  2007-10-11 8:46:48 }
 
end;

procedure TDNAMessage.Read(aName: string; aType: PTypeInfo; var Ptr);
begin
  case aType^.Kind of
    tkInteger: ReadInteger(aName, GetTypeData(aType)^.OrdType, Ptr);
    tkLString, tkString: ReadString(aName, GetTypeData(aType)^.OrdType, Ptr);
  end;
end;

procedure TDNAMessage.ReadInteger(aName: string; anOrdType : TOrdType;
  var Ptr);
var sze : byte;
    src : pointer;
begin
  src := @Ptr;
  sze := 0;
  case anOrdType of
    otSByte,
    otUByte : sze := SizeOf(byte);
    otSWord,
    otUWord : sze := SizeOf(word);
    otSLong,
    otULong : sze := SizeOf(integer);
  end;
  fStream.ReadBuffer(src^, sze);
end;

procedure TDNAMessage.ReadString(aName: string; anOrdType: TOrdType;
  var Ptr);
var
  sze : integer;
begin
  sze := 0;
  fStream.ReadBuffer(sze, SizeOf(sze));
  if (sze>0) then begin
    SetLength(string(Ptr), sze);
    fStream.ReadBuffer(string(Ptr)[1], sze);
  end
  else string(Ptr) := '';
end;

procedure TDNAMessage.Write(aName: string; aType: PTypeInfo; const Ptr);
begin
  case aType^.Kind of
    tkInteger: WriteInteger(aName, GetTypeData(aType)^.OrdType, Ptr);
    tkLString, tkString: WriteString(aName, GetTypeData(aType)^.OrdType, Ptr);
  end;
end;

procedure TDNAMessage.WriteInteger(aName: string; anOrdType : TOrdType;
  const Ptr);
var
  sze : byte;
  src : pointer;
begin
  { ToDo: make sure a Integer is always marshaled as Int32 }

  src := @Ptr;
  sze := 0;
  case anOrdType of
    otSByte,
    otUByte : sze := SizeOf(byte);
    otSWord,
    otUWord : sze := SizeOf(word);
    otSLong,
    otULong : sze := SizeOf(integer);
  end;

  fStream.Write(src^, sze);
end;

procedure TDNAMessage.WriteString(aName: string; anOrdType: TOrdType;
  const Ptr);
var
  sze : integer;
begin
  sze := Length(string(Ptr));
  fStream.Write(sze, SizeOf(sze));
  if (sze > 0) then
    fStream.Write(string(Ptr)[1], sze);
end;

end.

 

以上是我这些天学习RO得到的点心得,请大家多多指教

伟伟


推荐阅读
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • 本文讨论了一个数列求和问题,该数列按照一定规律生成。通过观察数列的规律,我们可以得出求解该问题的算法。具体算法为计算前n项i*f[i]的和,其中f[i]表示数列中有i个数字。根据参考的思路,我们可以将算法的时间复杂度控制在O(n),即计算到5e5即可满足1e9的要求。 ... [详细]
  • This article discusses the efficiency of using char str[] and char *str and whether there is any reason to prefer one over the other. It explains the difference between the two and provides an example to illustrate their usage. ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文介绍了一个在线急等问题解决方法,即如何统计数据库中某个字段下的所有数据,并将结果显示在文本框里。作者提到了自己是一个菜鸟,希望能够得到帮助。作者使用的是ACCESS数据库,并且给出了一个例子,希望得到的结果是560。作者还提到自己已经尝试了使用"select sum(字段2) from 表名"的语句,得到的结果是650,但不知道如何得到560。希望能够得到解决方案。 ... [详细]
  • 利用Visual Basic开发SAP接口程序初探的方法与原理
    本文介绍了利用Visual Basic开发SAP接口程序的方法与原理,以及SAP R/3系统的特点和二次开发平台ABAP的使用。通过程序接口自动读取SAP R/3的数据表或视图,在外部进行处理和利用水晶报表等工具生成符合中国人习惯的报表样式。具体介绍了RFC调用的原理和模型,并强调本文主要不讨论SAP R/3函数的开发,而是针对使用SAP的公司的非ABAP开发人员提供了初步的接口程序开发指导。 ... [详细]
  • 本文介绍了如何使用C#制作Java+Mysql+Tomcat环境安装程序,实现一键式安装。通过将JDK、Mysql、Tomcat三者制作成一个安装包,解决了客户在安装软件时的复杂配置和繁琐问题,便于管理软件版本和系统集成。具体步骤包括配置JDK环境变量和安装Mysql服务,其中使用了MySQL Server 5.5社区版和my.ini文件。安装方法为通过命令行将目录转到mysql的bin目录下,执行mysqld --install MySQL5命令。 ... [详细]
  • 浏览器中的异常检测算法及其在深度学习中的应用
    本文介绍了在浏览器中进行异常检测的算法,包括统计学方法和机器学习方法,并探讨了异常检测在深度学习中的应用。异常检测在金融领域的信用卡欺诈、企业安全领域的非法入侵、IT运维中的设备维护时间点预测等方面具有广泛的应用。通过使用TensorFlow.js进行异常检测,可以实现对单变量和多变量异常的检测。统计学方法通过估计数据的分布概率来计算数据点的异常概率,而机器学习方法则通过训练数据来建立异常检测模型。 ... [详细]
  • 第四章高阶函数(参数传递、高阶函数、lambda表达式)(python进阶)的讲解和应用
    本文主要讲解了第四章高阶函数(参数传递、高阶函数、lambda表达式)的相关知识,包括函数参数传递机制和赋值机制、引用传递的概念和应用、默认参数的定义和使用等内容。同时介绍了高阶函数和lambda表达式的概念,并给出了一些实例代码进行演示。对于想要进一步提升python编程能力的读者来说,本文将是一个不错的学习资料。 ... [详细]
  • 接下来要动手来做一个组件了,我想了一个计数器组件,功能方面是比较简单的,但这不是本章的重点,这一章的重点是说明一个组件的制作全过程。在其中可以学到很多组件制作的技巧,当然这些也是我从书上学得的。 ... [详细]
author-avatar
临海小少年
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有