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

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

伟伟

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值