gpt4 book ai didi

delphi - 使用 Delphi 实现透明远程处理的最简单解决方案是什么?

转载 作者:行者123 更新时间:2023-12-03 15:37:44 28 4
gpt4 key购买 nike

我有一个两层的 Delphi for Win32 应用程序,其中有很多业务逻辑在一个上帝对象中实现,我想外包到一个单独的服务中。这个单独的服务应该由多个客户端通过 TCP/IP telnet 风格的协议(protocol)访问。

如何让过渡变得最简单?

准确地说,我想保持这种简单性:我想每个函数只定义一次。例如,如果我想向我的应用程序添加 pin 码登录功能,我只需要定义

 function Login(Username: string; PinCode: integer): boolean;

在服务器上的某个对象中运行函数,然后我可以从客户端使用它,而无需任何额外的工作。

在最坏的情况下,我必须实现三个函数而不是一个。首先,服务器上的函数体本身,其次,解码器从网络接收文本行,将其解包并检查有效性:

 procedure HandleCommand(Cmd: string; Params: array of string);
begin
...
if SameText(Cmd, 'Login') then begin
CheckParamCount(Params, 2);
ServerObject.Login(
Params[0],
StrToInt(Params[1])
);
end;
end;

第三,编码器,当客户端调用时,打包参数并将它们发送到服务器:

function TServerConnection.Login(Username: string; PinCode: integer): boolean;
begin
Result := StrToBool(ServerCall('Login '+Escape(Username)+' '+IntToStr(PinCode)));
end;

显然,我不想要这个。

到目前为止,我已经成功摆脱了解码器。我使用 Delphi RTTI 编写了一个通用解码器,它按名称查找已发布的方法,检查参数并调用它。

现在我可以向服务器对象添加一个已发布的方法,并且可以从 telnet 调用它:

 function Login(Username: string; PinCode: integer): boolean;

> login john_locke
Missing parameter 2 (PinCode: integer)!

但是我该如何编写编码器呢?我无法动态获取服务器函数列表并将函数添加到客户端对象。我可能可以保留某种动态伪函数集合,但这会使我的客户端调用变得丑陋:

ServerConnection.Call('Login', [Username, Password]);

此外,这会破坏类型安全,因为每个参数都作为变体传递。如果可能的话,我想保持编译时类型安全。

也许客户端代码自动生成?我可能可以在我的服务器中编写“GetFunctionList()”和“GetFunctionPrototype(Name: string)”:

> GetFunctionList
Login
Logout
IsLoggedIn

> GetFunctionPrototype Login
function Login(Username: string; PinCode: integer): boolean;

这样每次我需要更新客户端时,我只需从服务器重新查询所有函数原型(prototype)并自动为它们生成编码器代码。但这会将编译与执行混合在一起:我必须首先编译服务器,然后启动它并查询其功能,然后构建客户端编码器并仅在之后重新编译客户端。复杂!

另一种选择是编写通用编码器函数,然后从所有客户端原型(prototype)函数调用它:

procedure TServerConnection.GenericMarshaller(); assembler;
asm
//finds the RTTI for the caller function, unwinds stack, pops out caller params,
//packs them according to RTTI and sends to the server.
//receives the result, pushes it to stack according to RTTI, quits
//oh god
end;

function TServerConnection.Login(Username: string; PinCode: integer): boolean; assembler;
asm
call GenericMarshaller
end;

这节省了我每次手动打包的时间(减少出错的机会),但仍然需要我手动将服务器函数原型(prototype)复制到客户端对象中。另外,编写这个通用编码器可能会是一个人间 hell 。

然后可以选择使用 RPC,但我不喜欢它,因为我需要重新定义 IDL 中的所有函数。 Delphi 的 IDL 编辑器很糟糕。对于 OLE 接口(interface),Delphi 强制生成“安全调用”函数,这也很糟糕。除了检查 RPC 类的每个函数调用之外,没有其他方法可以实现自动检测断开和自动恢复连接功能:

function TServerWrapper.Login(Username: string; PinCode: integer): boolean;
begin
try
RealObject.Login(Username, Pincode);
except
on E: EOleException do
if IndicatesDisconnect(E) then
Disconnect;
Reconnect;
RealObject.Login(Username, Pincode);
end;
end;

我们回到了多个函数,而不是一个。

那么,你们有什么建议呢?我还缺少哪些其他选择? Delphi 中是否有用于远程处理的常见模式或现成的解决方案?

最佳答案

就我个人而言,我认为您不应该基于透明远程处理来构建分布式系统。对于健壮且高性能的客户端-服务器交互来说,过程级 RPC 的粒度级别是错误的。让它变得可以容忍将迫使您编写定义不明确的程序,这些程序会执行大量操作并获取大量参数,只是为了避免繁琐的网络往返(=>大量小调用)API对性能和可靠性的影响。 p>

更多地从消息角度思考。考虑在客户端上构建一个消息队列以传递到服务器,也许使用与每个消息关联的回调来处理返回值(如果有)(匿名方法非常适合回调!)。然后,一次性将所有消息发送到服务器,并接收和解析结果,根据需要为每条处理的消息调用回调等。

如果您的服务器在将复合请求(来自客户端的消息队列)处理到事务中时有某种方式封装所有状态更改,那么它的效果会更好:您将获得一种处理第 n 个发生的错误的好方法message - 简单地丢弃在服务器上完成的所有工作,并继续处理,就好像客户端请求从未进入一样。这通常也简化了客户端对服务器状态的理解。

我过去曾围绕这些原则构建过系统,并且它们有效。使网络透明,假装系统的物理布局不存在,从长远来看只会带来痛苦。

关于delphi - 使用 Delphi 实现透明远程处理的最简单解决方案是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3917105/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com