感觉中的datasnap千孔百疮,到xe10已经具备冲击成千上万用户并发的能力了。应该放心用于项目实战了。补课研究10.1 datasnap开发手册。
用到的方法:
(1)TDBXCallback机制;
(2)TDServer.BroadcastMessage方法;
(3)TDSClientCallbackChanneManager1.RegisterCallback方法;
一、回叫的方式
1、服务器端回叫所有(同一信道)客户端
2、客户端回叫(同一信道)的其它客户端
3、客户端可以注册多个信道
server:
- 定义信道。定一条通道公路,然后搜索在此通道上跑的的car。得到每个客户ID
const DEMOChannel='DemoChannel';
2.服务器对客户端回调:
procedure TSMainFrm.mmMessageChange(Sender: TObject); var vMessage:TJSONString; begin vMessage := TJSONString.Create(mmMessage.Lines.Text); ServerContainer1.DSServer1.BroadcastMessage(DEMOChannel, vMessage); end;
3.对客户端注册通道和回调通道的搜索,由此得到通道中客户端的ID
procedure TForm1.btnListAllClientIdsClick(Sender: TObject); var aIdList : TList<String>; sId : String; begin aIdList := ServerContainer5.DSServer1.GetAllChannelClientId(DEMOChannel);{得到该通道中all的客户端ID} try for sId in aIdList do lbAllClientIds.Items.Add(sId); finally aIdList.Free; end; end;
procedure TForm1.btnListAllCallbackIdsClick(Sender: TObject); var aIdList : TList<String>; sId : String; begin aIdList := ServerContainer5.DSServer1.GetAllChannelCallbackId(DEMOChannel);{得到该回调通道中all的客户端ID try for sId in aIdList do lbAllCallbackIds.Items.Add(sId); finally aIdList.Free; end; end;
Client:
1、客户端注册
客户端注册回叫信道,由TDSClientCallbackChannelManager1.RegisterCallback方法实现;执行语句如下:
TDSClientCallbackChanneManager1.RegisterCallback(Combobox1.Text, TDemoCallback.Create);
现在我们看一看,客户端向服务器端注册回叫信道时,上述代码包含了注册回叫通道的四个要素:
(1)回叫通道ID,TDSClientCallbackChanneManager.ChannelNament属性值;相关字符应与服务器注册的“回叫信道”字符一致。
(2)客户端ID,TDSClientCallbackChanneManager.ManagerID属性值;每个客户端应明确一个唯一的识别码。
(3)回叫ID ,由TDSClientCallbackChanneManager1.RegisterCallback方法的第1个参数;
(4)回叫方法,由TDSClientCallbackChanneManager1.RegisterCallback第2个参数带入,创建TDemoCallback继承的方法,该对象复载Execute方法,就是用于回叫识别。
//首先继承类TDBXCallback
TDemoCallback = class(TDBXCallback) public constructor Create; function Execute(const Arg: TJSONValue): TJSONValue; override; end;
//TDemoCallback的excute方法。注意线程异步调用
function TDemoCallback.Execute(const Arg: TJSONValue): TJSONValue; var sDemoMessage : String; begin Result := TJSONTrue.Create; if (Arg is TJSONString) then begin sDemoMessage := TJSONString(Arg).Value; TThread.Synchronize(nil, procedure begin fmMainForm.mmDemoMessage.Lines.Text := sDemoMessage; end ); end; end;
procedure TfmMainForm.btnStartClick(Sender: TObject); begin SetupTask; EnableDisableButtons(False, True); DemoChannelManager.RegisterCallback(callbackId, DemoCallback.Create);//注册通道 end; procedure TfmMainForm.btnStopClick(Sender: TObject); begin EnableDisableButtons(True ,False); DemoChannelManager.UnregisterCallback(callbackId);//注销 end;
procedure TForm17.mmMessageChange(Sender: TObject);//服务器通过回调发送信息到该通道all客户端 var vMessage : TJSONString; begin vMessage := TJSONString.Create(mmMessage.Lines.Text); ServerContainer5.DSServer1.BroadcastMessage(DEMOChannel, vMessage);//发送信息到该通道DEMOChannel中all的客户端 end;
2、客户端与客户端之间的回叫,使用TDSAdminClient类别的NotifyCallback方法
XE在DSProxy单元,增加TDSAdminClient类别,强化回叫功能。其中TDSAdminClient类别的NotifyCallback方法用于客户端之间的回叫,可以回叫指定回叫通道中的特定客户端(客户端ID)或回叫识别(回叫ID)的客户端。声明如下:
function NotifyCallback(ChannelName:string; ClientID:string;CallbackID:string;Msg:TJSONValue; out Respones :TJSONValue):Boolean;
NotifyCallback方法的参数含意:
(1)ChannelName,回叫通道名称;
(2)ClientID,客户端识别;
(3)CallbackID,回叫识别;
(4)Msg,传递信息;
(5)Respones,被叫客户端的回传信息
procedure TfmMainForm.btnBroadcastToClientClick(Sender: TObject); var LClient: TDSAdminClient; LMessage: TJSONString; LResponse: TJSONValue; LConnection: TDBXConnection; begin LConnection := scnnCallbackServer.DBXConnection; LClient := TDSAdminClient.Create(LConnection, False); try LMessage := TJSONString.Create(Format('呼叫通道:%s,客户端识别:%s,回叫识别:%s,回叫信息:%s', [DemoChannelManager.ChannelName, cbClientIds.Text, cbCallbackIds.Text, mmChannelCallbacks.Text])); try LClient.NotifyCallback(DemoChannelManager.ChannelName, cbClientIds.Text, cbCallbackIds.Text, LMessage, LResponse); try if LResponse <> nil then edtResponse.Text := Format('客户端响应:%s', [LResponse.ToString]) else edtResponse.Text := Format('客户端响应:%s', ['nil']); finally LResponse.Free; end; finally LMessage.Free; end; finally LClient.Free; end; end;