multithreading - Delphi - 异步 Datasnap 方法调用
问题描述
我正在编写一个 Datasnap 应用程序,客户端/服务器之间有一个 TCP 连接,服务器连接到一个 SQL 服务器。
服务器有一个包含所有数据集查询和 SQL 连接的数据模块 DM1。DM1 还具有 REST 请求/客户端/响应组件。
DM1 有一个带有 ID 参数的公开函数 PostDataAsync:从数据集生成 json,然后 HTTP 将其发布到 RESTFul 服务。它返回回调 arg 中未能发布的记录数。
这个 DM1 的 DSServer 是“Invocation”。
调用服务器类型应确保每个服务器方法调用都有自己的DB连接、数据集、Rest组件,不会有多个调用相互干扰数据(如果添加并行线程)。
procedure TServerMethods1.postCustOrderHistAsync(CustomerID: String; callback: TDBXcallback);
var
jsonObject: TJSONObject;
CallbackValue: TJsonValue;
errors: Integer;
begin
errors := postCustOrderHist(CustomerID); //takes time to post, returns num of failed records
jsonObject := TJSONObject.create;
jsonObject.AddPair(tjsonpair.create('errors', errors.ToString));
CallbackValue := callback.Execute(jsonObject);
end;
客户端有一个按钮,它使用 ID 参数调用服务器方法 PostDataAsync,还有一个回调函数“ShowNotification”(它使用 Windows 通知中心显示 Post 通知状态)。
目前,应用程序的工作方式如下:客户端同步调用服务器函数,即主线程等待服务器函数完成HTTP post,然后运行回调通知;客户端同时挂起。
TDSCallbackWithMethod = class(TDBXCallback)
private
FCallbackMethod: TDSCallbackMethod;
public
constructor Create(ACallbackMethod: TDSCallbackMethod);
function Execute(const Args: TJSONValue): TJSONValue; override; //executes FCallbackMethod
end;
procedure TMainForm.BtnPostOrderHistoryClick(Sender: TObject);
var
callback: TDBXCallback;
ServerMethods1Client: TServerMethods1Client;
begin
//Define Callback to show notification
callback := TDSCallbackWithMethod.Create(
function(const Args: TJSONValue): TJSONValue
var
errors: integer;
begin
errors := Args.GetValue<integer>('errors');
if errors = 0 then
showNotification(StrSentSuccessfully)
else
showNotification(StrSendingFailed + '(' + errors.ToString + ' not sent)');
result := TJsonTrue.Create;
end);
//Call Server Method
ServerMethods1Client := TServerMethods1Client.Create(DMServerConnection.SQLConnection1.DBXConnection);
try
ServerMethods1Client.postCustOrderHistAsync(EditCustomerId.Text, callback)
finally
ServerMethods1Client.Free;
end;
end;
应该如何设计才能异步调用服务器方法,并让服务器在完成后运行回调?Post 函数应该能够被同一用户多次调用或同时调用多次。线程应该在服务器端还是客户端?如果有人可以提供帮助,我可以发送一个使用 Northwind 数据库的应用程序演示。
注意:我尝试在 TTask 中运行客户端函数调用,它在用户一次运行该函数时起作用。但是当服务器方法同时运行多次时,我得到一个“DBXError…读取错误…回调期望 X 得到 Y”。似乎在客户端等待第一个请求的响应回调格式时,它与从第二个请求发起的其他 tcp 协议数据包混淆了。我曾尝试在服务器端运行 ttask,但出现异常“TOLEDBCommand.Destroy - 未释放接口”
解决方案
看看这个例子,它介绍了创建回调的步骤。基本上,您需要一个 TDSClientCallbackChannelManager(组件)及其 RegisterCallback 函数来告诉 datasnap 客户端在从服务器触发回调时在客户端调用什么方法(从 TDBXCallback 继承的对象)。您需要将客户端会话 ID 传递给服务器,以便它可以使用 NotifyCallBack 调用正确的客户端。然后从该回调方法中,您可以在 TThread.Queue 中执行您需要的操作以确保安全。您可能需要在服务器返回的 JSON 中创建某种唯一标识符(或者您的 CustomerID 可能会起作用),以便您的客户端知道哪个调用是哪个调用的结果。
推荐阅读
- python - 了解 Pandas DataFrame 中 dtypes 支持类型的简单方法
- ios - 使用委托和 RxCocoa 显示“#selector”的参数是指未暴露给 Objective-C 的实例
- javascript - 在全屏页面上滚动添加图像到页面
- angular - NullInjectorError:没有 t 的提供者
- python - 保持示例索引与 tf.keras.predict 和 tf.data.Dataset 的对应关系
- amazon-web-services - Jenkins 登录后重定向到 Http
- operating-system - 逻辑地址空间大于物理和后备存储的总和
- django - 我应该在哪里处理诸如触发 django rest 框架中的通知之类的事情
- javascript - 我需要做一个倒计时
- c - 如何迭代这个 sin 方程?