日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

DataSnap的CallBack

 aaie_ 2014-01-18

DataSnap可以用TDBXCallBack的類進行服務端和客戶端以及客戶端與客戶端之間的通信。

在進行通信時要用到以下標識

服務端與客戶端通信:

    1.通道 

    2.客戶端注冊的回叫標識

客戶端與客戶端通信:

   1.通道

   2.客戶端注冊的回叫標識

   3.客戶端標識

一個客戶端一般只需要一個通道即可,一個通道可以注冊多個客戶端回叫標識,客戶端標識主要用于客戶端通信

開發(fā)時大體的步驟有以下幾點:

1.服務端

     用DSServer的BroadcastMessage函數進行發(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;

第一個函數時向ChannelName通道的所有在線客戶端發(fā)送信息,第二個函數時向ChannelName通道的CallBackID的客戶端發(fā)送信息,Msg是要發(fā)送的信息載體。

2.客戶端

  主要用到了TDSClientCallbackChannelManager類和TDSAdminClient類(DSProxy單元)及TDBXCallBack類。

  1).在工具箱是拖動DSClientCallbackChannelManager控件到窗體上,設置它的channelName\DSHostName\CommuncationProtocol\DSPort\ManagerID屬性等,然后用它的RegisterCallback事件向服務器注冊回叫標識即可。

 2) TDSAdminClient類主要用于向其它客戶端發(fā)送信息,主要用到此類的NotifyCallback函數

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是接收放的應答信息,主要是用到了客戶端的TDBXCallBack類,此類這些通信的基礎。

3)TDBXCallBack是個虛函數,需用戶重新產生一個子類并實現它的Execute的方法。服務端或客戶端在通信時會把這個子類當做參數進行傳遞。

以下為開發(fā)實例的載圖及其代碼:(最上面的窗體為服務端,右邊的為客戶端在虛擬機中,左下邊的為本機的客戶端)

以下為開發(fā)大體步驟:

1.開發(fā)服務端

菜單"File-New-Other-DataSnap Server "建立服務端程序,主要在主窗體上放上以下幾個控件:

兩個listbox,主要獲取客戶端所有的回叫標識和客戶端標識,兩上TRadioButton用于發(fā)送信息時確認是給同一通道的客戶發(fā)信息還是給指定的回叫標識發(fā)信息,這里主要用到了TJSONValue

以下為服務端主界面的源碼

復制代碼
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);   //獲取所有通道的回叫標識
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);  //獲取所有通道的客戶端標識
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('你要關閉服務嗎?',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.開發(fā)客戶端

建立應用程序并在菜單"File-New-DataSnap Server"選擇DataSnap Client Module選項,連接上面建立的服務程序并自動產生服務端的導出函數單元及DataModule類,在DataModule類上放TDSClientCallbackChannelManager控件,它主要用于向服務端注冊回叫標識,另它的ManagerID是用于客戶端的標識,千萬不要忘記它的相關屬性設置,否則其它電腦上的客戶端是無法訪問服務端的。

在客戶端主界面上放以下控件:

TMemo:用于顯示收到的信息

兩個Combobox,讓用戶輸入其它客戶端的回叫ID和客戶端標識ID,用于給其它客戶端發(fā)信息

一個Tedit,用于寫入要發(fā)送的信息內容,一個button用于發(fā)送動作

兩個TEdit,主要是讓程序在運行時讓用戶 輸入客戶端標識ID和客戶端回叫ID。

一個Tbutton用于手動注冊回叫事件

另加上一個TEdit,主要設置服務端的地址

以下為客戶端主界面源碼:

復制代碼
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;//一定要設置
    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('成功回叫客戶端'); //一定要回傳給服務端信息 ,在客戶端發(fā)送時會顯示
  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('請輸入相關標識.');
    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:='已成功連接服務器';

    if   ClientModule1.DSClientCallbackChannelManager1.RegisterCallback(callid,TDataSnapCallBack.Create) then
          StatusBar1.Panels[1].Text:='已成功注冊,CallID:'+Callid
    else
      StatusBar1.Panels[1].Text:='注冊CallID失敗.';
  end else
  begin
   StatusBar1.Panels[0].Text:='連接服務器失敗';
    i:=cbCallBack.Items.IndexOf(callid);
    cbCallBack.Items.Delete(i);     //刪除注冊失敗的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, 回叫識別: %s, 客戶端標識: %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('對方沒有回應') ;
         finally
           outMessage.Free;
         end;

       finally
          vMessage.Free;
       end;

    finally
      AC.Free;
    end;

  end;

end;




end.
復制代碼

 

在XE3下開發(fā),用tcp/ip

源碼下載地址:http://download.csdn.net/detail/yagzh2000/5303997

    本站是提供個人知識管理的網絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯系方式、誘導購買等信息,謹防詐騙。如發(fā)現有害或侵權內容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多