DataSnap可以用TDBXCallBack的類進(jìn)行服務(wù)端和客戶端以及客戶端與客戶端之間的通信。 在進(jìn)行通信時(shí)要用到以下標(biāo)識(shí) 服務(wù)端與客戶端通信: 1.通道 2.客戶端注冊(cè)的回叫標(biāo)識(shí) 客戶端與客戶端通信: 1.通道 2.客戶端注冊(cè)的回叫標(biāo)識(shí) 3.客戶端標(biāo)識(shí) 一個(gè)客戶端一般只需要一個(gè)通道即可,一個(gè)通道可以注冊(cè)多個(gè)客戶端回叫標(biāo)識(shí),客戶端標(biāo)識(shí)主要用于客戶端通信 開(kāi)發(fā)時(shí)大體的步驟有以下幾點(diǎn): 1.服務(wù)端 用DSServer的BroadcastMessage函數(shù)進(jìn)行發(fā)送信息 function BroadcastMessage(const ChannelName: string; const Msg: TJSONValue; const ArgType: Integer = TDBXCallback.ArgJson): Boolean; overload; function BroadcastMessage(const ChannelName: string; const CallbackId: string; const Msg: TJSONValue; const ArgType: Integer = TDBXCallback.ArgJson): Boolean; overload; 第一個(gè)函數(shù)時(shí)向ChannelName通道的所有在線客戶端發(fā)送信息,第二個(gè)函數(shù)時(shí)向ChannelName通道的CallBackID的客戶端發(fā)送信息,Msg是要發(fā)送的信息載體。 2.客戶端 主要用到了TDSClientCallbackChannelManager類和TDSAdminClient類(DSProxy單元)及TDBXCallBack類。 1).在工具箱是拖動(dòng)DSClientCallbackChannelManager控件到窗體上,設(shè)置它的channelName\DSHostName\CommuncationProtocol\DSPort\ManagerID屬性等,然后用它的RegisterCallback事件向服務(wù)器注冊(cè)回叫標(biāo)識(shí)即可。 2) TDSAdminClient類主要用于向其它客戶端發(fā)送信息,主要用到此類的NotifyCallback函數(shù) function NotifyCallback(ClientId: string; CallbackId: string; Msg: TJSONValue; out Response: TJSONValue): Boolean; overload; function NotifyCallback(ChannelName: string; ClientId: string; CallbackId: string; Msg: TJSONValue; out Response: TJSONValue): Boolean; overload; deprecated 'ChannelName is no longer required'; msg要發(fā)信息的載體,Response是接收放的應(yīng)答信息,主要是用到了客戶端的TDBXCallBack類,此類這些通信的基礎(chǔ)。 3)TDBXCallBack是個(gè)虛函數(shù),需用戶重新產(chǎn)生一個(gè)子類并實(shí)現(xiàn)它的Execute的方法。服務(wù)端或客戶端在通信時(shí)會(huì)把這個(gè)子類當(dāng)做參數(shù)進(jìn)行傳遞。 以下為開(kāi)發(fā)實(shí)例的載圖及其代碼:(最上面的窗體為服務(wù)端,右邊的為客戶端在虛擬機(jī)中,左下邊的為本機(jī)的客戶端) 以下為開(kāi)發(fā)大體步驟: 1.開(kāi)發(fā)服務(wù)端 菜單"File-New-Other-DataSnap Server "建立服務(wù)端程序,主要在主窗體上放上以下幾個(gè)控件: 兩個(gè)listbox,主要獲取客戶端所有的回叫標(biāo)識(shí)和客戶端標(biāo)識(shí),兩上TRadioButton用于發(fā)送信息時(shí)確認(rèn)是給同一通道的客戶發(fā)信息還是給指定的回叫標(biāo)識(shí)發(fā)信息,這里主要用到了TJSONValue 以下為服務(wù)端主界面的源碼 unit UFrmServer; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls; type TForm1 = class(TForm) GroupBox2: TGroupBox; lbCallBackID: TListBox; btnAllCallBackID: TButton; edtMessage: TEdit; btnSend: TButton; rbAll: TRadioButton; rbSingle: TRadioButton; GroupBox1: TGroupBox; btnAllClientID: TButton; lbClientID: TListBox; procedure btnAllCallBackIDClick(Sender: TObject); procedure btnAllClientIDClick(Sender: TObject); procedure btnSendClick(Sender: TObject); procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation uses ServerContainerUnit1,System.Generics.Collections,Data.DBXJSON; {$R *.dfm} const channel='test'; procedure TForm1.btnAllCallBackIDClick(Sender: TObject); //獲取所有通道的回叫標(biāo)識(shí) var ls:TList<string>; ea:TList<string>.TEnumerator; begin lbCallBackID.Clear; ls:=ServerContainerUnit1.ServerContainer1.DSServer1.GetAllChannelCallbackId(channel); ea:=ls.GetEnumerator; while ea.MoveNext do lbCallBackID.Items.Add(ea.Current); ls.Free; end; procedure TForm1.btnAllClientIDClick(Sender: TObject); //獲取所有通道的客戶端標(biāo)識(shí) var ls:TList<string>; ea:TList<string>.TEnumerator; begin lbClientID.Clear; ls:=ServerContainerUnit1.ServerContainer1.DSServer1.GetAllChannelClientId(channel); ea:=ls.GetEnumerator; while ea.MoveNext do lbClientID.Items.Add(ea.Current); ls.Free; end; procedure TForm1.btnSendClick(Sender: TObject); //發(fā)送信息 var js:TJsonString; callid:string; begin js:=TJSONString.Create(edtMessage.Text); if rbAll.Checked then ServerContainer1.DSServer1.BroadcastMessage(channel,js) else begin callid:=lbCallBackID.Items.Strings[lbCallBackID.ItemIndex]; if callid<>'' then ServerContainerUnit1.ServerContainer1.DSServer1.BroadcastMessage(channel,callid,js); end; end; procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean); begin if MessageDlg('你要關(guān)閉服務(wù)嗎?',mtInformation,[mbYes,mbNo],0,mbno)=idno then CanClose:=False else begin if ServerContainerUnit1.ServerContainer1.DSServer1.Started then ServerContainerUnit1.ServerContainer1.DSServer1.Stop; CanClose:=True; end; end; end. 2.開(kāi)發(fā)客戶端 建立應(yīng)用程序并在菜單"File-New-DataSnap Server"選擇DataSnap Client Module選項(xiàng),連接上面建立的服務(wù)程序并自動(dòng)產(chǎn)生服務(wù)端的導(dǎo)出函數(shù)單元及DataModule類,在DataModule類上放TDSClientCallbackChannelManager控件,它主要用于向服務(wù)端注冊(cè)回叫標(biāo)識(shí),另它的ManagerID是用于客戶端的標(biāo)識(shí),千萬(wàn)不要忘記它的相關(guān)屬性設(shè)置,否則其它電腦上的客戶端是無(wú)法訪問(wèn)服務(wù)端的。 在客戶端主界面上放以下控件: TMemo:用于顯示收到的信息 兩個(gè)Combobox,讓用戶輸入其它客戶端的回叫ID和客戶端標(biāo)識(shí)ID,用于給其它客戶端發(fā)信息 一個(gè)Tedit,用于寫(xiě)入要發(fā)送的信息內(nèi)容,一個(gè)button用于發(fā)送動(dòng)作 兩個(gè)TEdit,主要是讓程序在運(yùn)行時(shí)讓用戶 輸入客戶端標(biāo)識(shí)ID和客戶端回叫ID。 一個(gè)Tbutton用于手動(dòng)注冊(cè)回叫事件 另加上一個(gè)TEdit,主要設(shè)置服務(wù)端的地址 以下為客戶端主界面源碼: unit UMain; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,Data.DBXJSON, Vcl.StdCtrls, Vcl.ComCtrls; type TFrmClient = class(TForm) GroupBox1: TGroupBox; mmReceive: TMemo; StatusBar1: TStatusBar; edtCallBack: TEdit; Label1: TLabel; Button1: TButton; Label2: TLabel; edtServer: TEdit; GroupBox2: TGroupBox; edtSend: TEdit; btnSend: TButton; Label3: TLabel; Label4: TLabel; cbCallBack: TComboBox; cbClientID: TComboBox; label5: TLabel; edtClientID: TEdit; procedure btnSendClick(Sender: TObject); procedure Button1Click(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure FormCreate(Sender: TObject); private { Private declarations } procedure RegisterCallBackID; function ConnectServer:Boolean; procedure AddCombobox(const ClientID,CallID:string); procedure SendMsgToOtherClient; public { Public declarations } end; type TDataSnapCallBack = class(TDBXCallback) private { private declarations } protected { protected declarations } public { public declarations } function Execute(const Arg: TJSONValue): TJSONValue;override; published { published declarations } end; var FrmClient: TFrmClient; callid:string; const channel='test'; implementation uses ClientModuleUnit1,Data.SqlExpr,Data.DBXCommon,Datasnap.DSProxy; {$R *.dfm} function TFrmClient.ConnectServer: Boolean; begin Result:=false; with ClientModule1.SQLConnection1 do begin Params.Clear; with ConnectionData.Properties do begin Values[TDBXPropertyNames.DriverName]:='DataSnap'; Values[TDBXPropertyNames.CommunicationProtocol]:='tcp/ip'; Values[TDBXPropertyNames.HostName]:=edtServer.Text; Values[TDBXPropertyNames.Port]:='211'; Values[TDBXPropertyNames.BufferKBSize]:='32'; Values[TDBXPropertyNames.DatasnapContext]:='datasnap/'; end; LoginPrompt:=False; try ClientModule1.SQLConnection1.Open; Result:=ClientModule1.SQLConnection1.ConnectionState=csStateOpen; ClientModuleUnit1.ClientModule1.DSClientCallbackChannelManager1.DSHostname:=edtServer.Text;//一定要設(shè)置 except end; end; end; procedure TFrmClient.FormCreate(Sender: TObject); begin end; { TDataSnapCallBack } function TDataSnapCallBack.Execute(const Arg: TJSONValue): TJSONValue; var str:string; begin Result:=TJSONString.Create('成功回叫客戶端'); //一定要回傳給服務(wù)端信息 ,在客戶端發(fā)送時(shí)會(huì)顯示 if Assigned(Arg) then if (Arg is TJSONString) then begin str:=TJSONString(Arg).Value; TThread.Synchronize(nil, procedure //匿名方法 begin FrmClient.mmReceive.Lines.Add(str); end ); end; end; procedure TFrmClient.AddCombobox(const ClientID,CallID:string); begin if cbClientID.Items.IndexOf(clientID)=-1 then cbClientID.Items.Add(ClientID); if cbCallBack.Items.IndexOf(CallID)=-1 then cbCallBack.Items.Add(CallID); end; procedure TFrmClient.btnSendClick(Sender: TObject); begin SendMsgToOtherClient; end; procedure TFrmClient.Button1Click(Sender: TObject); begin if (edtCallBack.Text='') or (edtClientID.Text='') then begin ShowMessage('請(qǐng)輸入相關(guān)標(biāo)識(shí).'); exit; end; RegisterCallBackID; end; procedure TFrmClient.FormClose(Sender: TObject; var Action: TCloseAction); begin if ClientModuleUnit1.ClientModule1.SQLConnection1.ConnectionState=csStateOpen then begin ClientModule1.DSClientCallbackChannelManager1.UnregisterCallback(callid); ClientModule1.SQLConnection1.Close; end; end; procedure TFrmClient.RegisterCallBackID; var i:Integer; begin // callid:=DateTimeToStr(now); AddCombobox(edtClientID.Text,edtCallBack.Text); callid:= edtCallBack.Text; ClientModule1.DSClientCallbackChannelManager1.ManagerId:=edtClientID.Text; if ConnectServer then begin StatusBar1.Panels[0].Text:='已成功連接服務(wù)器'; if ClientModule1.DSClientCallbackChannelManager1.RegisterCallback(callid,TDataSnapCallBack.Create) then StatusBar1.Panels[1].Text:='已成功注冊(cè),CallID:'+Callid else StatusBar1.Panels[1].Text:='注冊(cè)CallID失敗.'; end else begin StatusBar1.Panels[0].Text:='連接服務(wù)器失敗'; i:=cbCallBack.Items.IndexOf(callid); cbCallBack.Items.Delete(i); //刪除注冊(cè)失敗的id end; end; procedure TFrmClient.SendMsgToOtherClient; var AC:TDSAdminClient; //發(fā)送消息管理類 vMessage:TJSONString; outMessage:TJSONValue; clientID,CallbackID,sMessage:string; begin if ConnectServer then begin clientID:=cbClientID.Text; CallbackID:=cbCallBack.Text; AC:=TDSAdminClient.Create(ClientModule1.SQLConnection1.DBXConnection,False); sMessage:=Format('呼叫通道: %s, 回叫識(shí)別: %s, 客戶端標(biāo)識(shí): %s, 發(fā)送信息: %s',[channel,callbackid,clientid,edtSend.Text]); try vMessage:=TJSONString.Create(sMessage); try AC.NotifyCallback(channel,clientID,CallbackID,vMessage,outMessage); try if Assigned(outMessage) then mmReceive.Lines.Add(Format('返回信息: %s',[outmessage.ToString])) else mmReceive.Lines.Add('對(duì)方?jīng)]有回應(yīng)') ; finally outMessage.Free; end; finally vMessage.Free; end; finally AC.Free; end; end; end; end.
在XE3下開(kāi)發(fā),用tcp/ip 源碼下載地址:http://download.csdn.net/detail/yagzh2000/5303997 |
|
來(lái)自: aaie_ > 《datasnap》