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

原创 2007年10月11日 09:10:00

                     根据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得到的点心得,请大家多多指教

伟伟

RemObjects SDK Source For Delphi XE7

根据网上RemObjects SDK for Delphi - 7.0.63.1055 retail Full Source源码版本修改支持Delphi XE7。...
  • tht2009
  • tht2009
  • 2014年09月25日 09:15
  • 8309

RemObject解决自动生成代码的想法.

        用过DELPHI写过多层框架的,可能能RemObject比较熟悉. RemObjects Service Builder 自动生成代码的同时,也给我们带来困扰. 每个类都要定义在int...
  • wangyunyong0905
  • wangyunyong0905
  • 2007年10月10日 13:30
  • 875

实现RemObject Hydra实现插件库注意要点

一、控制模块 每个插件库(DLL)都要有且只有一个控制模块,取名就叫ModuleController就行了。 二、不可视插件 用向导生成,最关键的是名字,例如下面代码中字符串部分就是插件名字,生成插件...
  • cmd9x
  • cmd9x
  • 2014年02月20日 18:11
  • 822

Java RMI远程方法调用详解

远程方法调用RMI(Remote Method Invocation),是允许运行在一个Java虚拟机的对象调用运行在另一个Java虚拟机上的对象的方法。 这两个虚拟机可以是运行在相同计算机上的不同进...
  • guyuealian
  • guyuealian
  • 2016年07月22日 17:45
  • 9286

Java远程方法调用

主要参考 http://www.kaixinwenda.com/article-yxc135-7690958.html http://bbs.chinaunix.net/thread-117931...
  • sunmenggmail
  • sunmenggmail
  • 2013年01月26日 10:09
  • 7068

RPC 远程调用 原理

RPC(Remote Procedure Call Protocol)——远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在...
  • aflydreams
  • aflydreams
  • 2017年01月19日 22:25
  • 358

远程调用的几种方式

在分布式服务框架中,最基础的问题就是远程服务是怎么通讯的。首先来看看计算机系统网络通信的基本原理,网络通信需要做的就是将流从一台计算机传输到另外一台计算 机,基于传输协议和网络IO来实现,其中传输协...
  • kanglix1an
  • kanglix1an
  • 2015年06月29日 20:28
  • 2670

dubbo_远程同步调用原理

Dubbo缺省协议采用单一长连接和NIO异步通讯,适合于小数据量大并发的服务调用,以及服务消费者机器数远大于服务提供者机器数的情况。   Dubbo缺省协议,使用基于mina1.1.7...
  • taotoxht
  • taotoxht
  • 2017年03月13日 09:26
  • 711

在java中实现远程方法调用

1. RMI概述 RMI(Remote MethodInvocation)是分布对象软件包,简化了在多台计算机上的Java应用之间的通信,使用的JDK版本必须在1.1以上。用到的类有两个:第一jav...
  • libaolin198706231987
  • libaolin198706231987
  • 2016年01月06日 15:42
  • 1602

开发中常用的五种远程调用方式

一、综述 本文比较了RMI,Hessian,Burlap,Httpinvoker,web service等5种通讯协议的在不同的数据结构和不同数据量时的传输性能。 RMI是java语言本身提供的远...
  • xujiangdong1992
  • xujiangdong1992
  • 2017年07月31日 14:08
  • 368
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:根据RemObject的远程方法调用原理实现的简单远程方法调用
举报原因:
原因补充:

(最多只允许输入30个字)