DELPHI盒子
!实时搜索: 盒子论坛 | 注册用户 | 修改信息 | 退出
检举帖 | 全文检索 | 关闭广告 | 捐赠
技术论坛
 用户名
 密  码
自动登陆(30天有效)
忘了密码
≡技术区≡
DELPHI技术
lazarus/fpc/Free Pascal
移动应用开发
Web应用开发
数据库专区
报表专区
网络通讯
开源项目
论坛精华贴
≡发布区≡
发布代码
发布控件
文档资料
经典工具
≡事务区≡
网站意见
盒子之家
招聘应聘
信息交换
论坛信息
最新加入: sy1012
今日帖子: 0
在线用户: 10
导航: 论坛 -> 文档资料 斑竹:liumazi,ruralboy  
作者:
男 jopher3 (樵夫的马六甲) ▲▲▲▲▲ -
普通会员
2017/1/22 12:45:40
标题:
为Delphi移动开发准备的跨平台异步Socket 浏览:4376
加入我的收藏
楼主: 一、引言
    在D10.1 Berlin之前,Delphi移动开发一直缺少一个使用方便、跨平台的异步socket控件,除了Indy组件,连最基本的socket单元都缺少。所以,移动开发时实现移动客户端和电脑服务器之间、手机之间的异步通信比较困难。本人以前在实现手机端的消息传输时,还是通过HTTP轮询形式实现,响应速度慢、服务端压力大,不适合大并发即时通信开发。

    D10.1 Berlin版本发布之后,这样的局面改观了,因为Berlin中提供了一个跨平台Socket单元,尽管不是异步的,但是,通过我们通过使用多线程等技术的再度封装,就可以实现异步通信——收到消息、连通、断开、出错等,都激发相应的事件。本人近日就为QuickBurro中间件的移动开发组件增加了一个跨平台的异步Socket控件: TMBSocket。下面的代码是类声明,后图示意其属性、事件:

type
   TConnectedEvent = procedure(Sender: TObject; Socket: TSocket) of object;
   TDisconnectedEvent = procedure(Sender: TObject; Socket: TSocket) of Object;
   TDataArrivedEvent = procedure(Sender: TObject; Socket: TSocket) of Object;
   TErrorEvent = procedure(Sender: TObject; Socket: TSocket; const Error: string; var CanClose: boolean) of Object;
   //
   TMBSocket=class(TComponent)
   private
      RawSocket: TSocket;
      fHostName: string;
      fHostAddress: string;
      fPort: integer;
      fActive: boolean;
      fConnected: boolean;
      //
      fOnConnect: TConnectedEvent;
      fOnDisconnect: TDisconnectedEvent;
      fOnDataArrive: TDataArrivedEvent;
      fOnError: TErrorEvent;
      //
      procedure SetHostName(aHostName: string);
      procedure SetHostAddress(aHostAddress: string);
      procedure SetPort(aPort: integer);
      procedure SetActive(aActive: boolean);

   public
      constructor Create(AOwner: TComponent); override;
      destructor Destroy(); override;
      procedure Open;
      procedure Close;
      function SendBuff(const BufferPtr: pointer; const DataLength: integer): boolean;
      procedure ReceiveData(const BufferPtr: pointer; const Bytes: integer);
      function DataLength(): integer;

   published
      property HostName: string read fHostName write SetHostName;
      property HostAddress: string read fHostAddress write SetHostAddress;
      property Port: integer read fPort write SetPort;
      property Active: boolean read fActive write SetActive;
      property Connected: boolean read fConnected;
      //
      property OnConnect: TConnectedEvent read fOnConnect write fOnConnect;
      property OnDisconnect: TDisconnectedEvent read fOnDisconnect write fOnDisconnect;
      property OnDataArrive: TDataArrivedEvent read fOnDataArrive write fOnDataArrive;
      property OnError: TErrorEvent read fOnError write fOnError;
   End;
此帖子包含附件:
PNG 图像
大小:21.1K
----------------------------------------------
樵夫的大马甲
作者:
男 jopher3 (樵夫的马六甲) ▲▲▲▲▲ -
普通会员
2017/1/22 12:46:11
1楼: 二、电脑端服务程序
    为了测试手机端TMBSocket控件的异步通信效果,我们先用TServerSocket快速搭建一个测试服务器,让它与手机端程序进行通信。下面是代码和运行效果:

unit main;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, BurroSocket;

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Label1: TLabel;
    Edit1: TEdit;
    Server: TBServerSocket;
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Button4: TButton;
    Memo2: TMemo;
    procedure Button4Click(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure ServerListen(Sender: TObject; Socket: TBCustomWinSocket);
    procedure ServerClientRead(Sender: TObject; Socket: TBCustomWinSocket);
    procedure ServerClientConnect(Sender: TObject; Socket: TBCustomWinSocket);
    procedure ServerClientDisconnect(Sender: TObject;
      Socket: TBCustomWinSocket);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//
// 开启服务...
procedure TForm1.Button1Click(Sender: TObject);
begin
   server.Port:=strtoint(edit1.Text);
   server.Active:=true;
end;

//
// 停止服务...
procedure TForm1.Button3Click(Sender: TObject);
begin
   server.Active:=false;
   memo1.Lines.Add('');
   memo1.Lines.Add(formatdatetime('hh:nn:ss',now)+': ==>服务器顺利停止服务。');
end;

//
// 客户端连上来时...
procedure TForm1.ServerClientConnect(Sender: TObject;
  Socket: TBCustomWinSocket);
begin
   memo1.Lines.Add('');
   memo1.Lines.Add(formatdatetime('hh:nn:ss',now)+': <--有客户端连上来了!IP='+string(Socket.RemoteAddress));
end;

//
// 客户端断开时...
procedure TForm1.ServerClientDisconnect(Sender: TObject;
  Socket: TBCustomWinSocket);
begin
   memo1.Lines.Add('');
   memo1.Lines.Add(formatdatetime('hh:nn:ss',now)+': <--有客户端断开了!IP='+string(Socket.RemoteAddress));
end;

//
// 客户端数据送达时...
procedure TForm1.ServerClientRead(Sender: TObject; Socket: TBCustomWinSocket);
var
   j: integer;
   tmpstr: ansistring;
begin
   j:=socket.ReceiveLength;
   setlength(tmpstr,j);
   Socket.ReceiveBuf(tmpstr[1],j);
   memo1.Lines.Add('');
   memo1.Lines.Add(formatdatetime('hh:nn:ss',now)+': <--收到'+inttostr(j)+'个字节:');
   memo1.Lines.Add(string(tmpstr));
end;

//
// 向第一个客户端连接发送测试数据...
procedure TForm1.Button2Click(Sender: TObject);
var
   tmpstr: ansistring;
begin
   tmpstr:=ansistring(memo2.Lines.Text);
   server.Socket.Connections[0].SendBuf(tmpstr[1],length(tmpstr));
   memo1.Lines.Add('');
   memo1.Lines.Add(formatdatetime('hh:nn:ss',now)+': ==>向客户端发送了如下消息:');
   memo1.Lines.Add(string(tmpstr));
end;

//
// 服务端口开始工作时...
procedure TForm1.ServerListen(Sender: TObject; Socket: TBCustomWinSocket);
begin
   memo1.Lines.Add('');
   memo1.Lines.Add(formatdatetime('hh:nn:ss',now)+': ==>服务器已启动,请手机端开始测试!');
end;

//
// 退出程序...
procedure TForm1.Button4Click(Sender: TObject);
begin
   close;
end;

end.
此帖子包含附件:
PNG 图像
大小:6.8K
----------------------------------------------
樵夫的大马甲
作者:
男 jopher3 (樵夫的马六甲) ▲▲▲▲▲ -
普通会员
2017/1/22 12:46:42
2楼: 三、移动端异步通信测试程序
    万事具备,我们来编写个手机端的异步通信客户端程序,让它与上面的简易测试服务器进行通信。下面是测试程序源码、运行效果图:

unit main;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, System.net.socket,
  FMX.Objects, FMX.StdCtrls, FMX.Controls.Presentation, FMX.ScrollBox, FMX.Memo,
  MBSocket;

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Rectangle1: TRectangle;
    Button3: TButton;
    Button4: TButton;
    Button5: TButton;
    Rectangle2: TRectangle;
    Label1: TLabel;
    Button2: TButton;
    Image1: TImage;
    Memo2: TMemo;
    MBSocket: TMBSocket;
    Button1: TButton;
    Image2: TImage;
    StyleBook1: TStyleBook;
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure MBSocketConnect(Sender: TObject; Socket: TSocket);
    procedure MBSocketError(Sender: TObject; Socket: TSocket;
      const Error: string; var CanClose: Boolean);
    procedure MBSocketDisconnect(Sender: TObject; Socket: TSocket);
    procedure MBSocketDataArrive(Sender: TObject; Socket: TSocket);
    procedure Button4Click(Sender: TObject);
    procedure Button5Click(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

//
// 清提示区...
procedure TForm1.Button1Click(Sender: TObject);
begin
   memo1.Lines.Clear;
end;

//
// 退出程序...
procedure TForm1.Button2Click(Sender: TObject);
begin
   close;
end;

//
// 连接服务器...
procedure TForm1.Button3Click(Sender: TObject);
begin
   try
      mbsocket.Open;
   except
      on e:exception do
         memo1.Lines.Add(formatdatetime('hh:nn:ss',now)+': ==>连接服务器失败!'+e.ClassName+'-'+e.Message);
   end;
end;

//
// 发送数据...
procedure TForm1.Button4Click(Sender: TObject);
var
   tmpstr: string;
   data: TBytes;
begin
   tmpstr:=memo2.Lines.Text;
   Data:=TEncoding.Convert(TEncoding.Default,TEncoding.GetEncoding(936),bytesof(tmpstr));
   memo1.Lines.Add('');
   if MBSocket.SendBuff(@Data[0],length(Data)) then
      begin
         memo1.Lines.Add(formatdatetime('hh:nn:ss',now)+': ==>发送数据到服务器成功:');
         memo1.Lines.Add(tmpstr);
      end
   else
      memo1.Lines.Add(formatdatetime('hh:nn:ss',now)+': ==>发送数据到服务器失败!')
end;

//
// 断开...
procedure TForm1.Button5Click(Sender: TObject);
begin
   MBSocket.Close;
end;

//
// 连接成功的事件...
procedure TForm1.MBSocketConnect(Sender: TObject; Socket: TSocket);
begin
   memo1.Lines.Add('');
   memo1.Lines.Add(formatdatetime('hh:nn:ss',now)+': <-- 连接服务器成功!');
end;

//
// 收到数据的事件,接收数据并显示...
procedure TForm1.MBSocketDataArrive(Sender: TObject; Socket: TSocket);
var
   j: integer;
   tmpstr: string;
   data: TBytes;
begin
//
// 取待接收数据的长度...
   j:=MBSocket.DataLength;
//
// 接收数据到缓冲区...
   setlength(data,j);
   MBSocket.ReceiveData(@data[0],j);
//
// 显示数据...
   tmpstr:=StringOf(TEncoding.Convert(TEncoding.GetEncoding(936),TEncoding.Default,Data));
   memo1.Lines.Add('');
   memo1.Lines.Add(formatdatetime('hh:nn:ss',now)+': <-- 共有'+inttostr(j)+'字节的数据送达:');
   memo1.Lines.Add(tmpstr);
end;

//
// 断开事件...
procedure TForm1.MBSocketDisconnect(Sender: TObject; Socket: TSocket);
begin
   memo1.Lines.Add('');
   memo1.Lines.Add(formatdatetime('hh:nn:ss',now)+': <-- 与服务器断开了!');
end;

//
// 通信错误...
procedure TForm1.MBSocketError(Sender: TObject; Socket: TSocket;
  const Error: string; var CanClose: Boolean);
begin
   memo1.Lines.Add('');
   memo1.Lines.Add(formatdatetime('hh:nn:ss',now)+': <-- 发生了通信错误:'+error);
   CanClose:=false;
end;

end.
此帖子包含附件:
JPEG 图像
大小:161.4K
----------------------------------------------
樵夫的大马甲
作者:
男 jopher3 (樵夫的马六甲) ▲▲▲▲▲ -
普通会员
2017/1/22 12:46:58
3楼: 四、结束语
    通过测试,我们发现这种方法完全支持跨平台及长连接,异步效果也不错! 在此,为EMB公司点个赞! 非常给力!
    然后,我们在TMBSocket基础上,实现真正的即时通信、结合Service实现手机消息推送等,就变得轻而易举的了。杠杆给你了,撬地球吧!
----------------------------------------------
樵夫的大马甲
作者:
男 zhipu (zhipu) ★☆☆☆☆ -
普通会员
2017/1/22 13:08:19
4楼: delphi牛人!
----------------------------------------------
-
作者:
男 cnhotel (cnhotel) ★☆☆☆☆ -
盒子活跃会员
2017/1/22 15:19:40
5楼: 膜拜大神。
----------------------------------------------
-
作者:
男 blueflag (昆了) ★☆☆☆☆ -
盒子活跃会员
2017/1/22 22:23:16
6楼: 牛逼~ 一直没有钱买你的框架,好痛苦
----------------------------------------------
-
作者:
男 jopher3 (樵夫的马六甲) ▲▲▲▲▲ -
普通会员
2017/1/23 8:14:31
7楼: 楼上的,年底促销,抓住机会呀!

企业版5折,只要3.98K
OEM版4折,只要4.98K

一次购买永久使用、无项目数限制、升级免费
另外还送春节源码礼包、送上咱的一份实惠祝福!
----------------------------------------------
樵夫的大马甲
作者:
男 zhoupower (power) ★☆☆☆☆ -
普通会员
2017/1/23 9:10:09
8楼: 高人,能不能介绍详细一点,也便于推广
----------------------------------------------
-
作者:
男 jopher3 (樵夫的马六甲) ▲▲▲▲▲ -
普通会员
2017/1/23 9:16:33
9楼: 浏览网站可了解概况:
   http://www.quickburro.org/

淘宝网店可直接下单购买:
   https://shop145791957.taobao.com/?spm=a1z10.1-c.0.0.pKSYMh&qq-pf-to=pcqq.group

加QQ群也可下载、参与技术交流:
   202675246、79114999、18594635

感谢各位大佬支持!
----------------------------------------------
樵夫的大马甲
作者:
男 jopher3 (樵夫的马六甲) ▲▲▲▲▲ -
普通会员
2017/1/24 6:55:19
10楼: 顶一个,支持正版!
----------------------------------------------
樵夫的大马甲
作者:
男 abcjingtong (jingtong) ★☆☆☆☆ -
普通会员
2017/1/25 9:38:55
11楼: 我现在用的DIOCP,支持移动端
----------------------------------------------
18114532@qq.com
作者:
男 u1427796291 (w1427796291) ▲▲▲▲△ -
普通会员
2017/1/29 14:46:26
12楼: 服务器接收巨量的并发
我使用linux+php+swoole解决方案。
简单快速高效 并发量大 稳定
----------------------------------------------
Nothing
作者:
男 chonghai (DBlue) ★☆☆☆☆ -
盒子活跃会员
2017/1/31 11:21:23
13楼: 支持,顶一个。
----------------------------------------------
喜欢Delphi,关注Delphi,愿和广大爱好者交朋友。
作者:
男 jopher3 (樵夫的马六甲) ▲▲▲▲▲ -
普通会员
2017/2/14 23:23:27
14楼: 基于此控件,本人已经为咱的QuickBurro中间件实现了一个新的长连接异步消息通信控件:TMBMessager。终于可以不再使用HTTP轮询来实现敏捷的消息通信了,实时、快速、支持较大并发、异步事件驱动、支持分组等等。 下面是此消息传输体系的示意图:
此帖子包含附件:
PNG 图像
大小:128.3K
----------------------------------------------
樵夫的大马甲
作者:
男 jopher3 (樵夫的马六甲) ▲▲▲▲▲ -
普通会员
2017/2/14 23:33:10
15楼: 此控件的类声明如下:

   TMBMessager=class(TComponent)
   private
      fActive: boolean;
      fConnection: TMBConnection;
      fHeartbeatInterval: integer;
      fMessagePort: integer;
      fConnectionId: int64;
      fLastError: string;
      //
      fOnChannelClosed: TChannelClosedEvent;
      fOnChannelOpened: TChannelOpenedEvent;
      fOnAllConnectionsMessage: TMessageEvent;
      fOnSingleConnectionMessage: TMessageEvent;
      fOnIntPropConnectionsMessage: TMessageEvent;
      fOnStrPropConnectionsMessage: TMessageEvent;
      fOnRoleIdConnectionsMessage: TMessageEvent;
      fOnCallbackMessage: TCallbackMessageEvent;
      fOnUnknownMessage: TUnknownMessageEvent;
      fOnHeartbeat: THeartbeatEvent;
      //
      MainSocket: TMBSocket;
      DataBuff: TBytes;
      http: TIdHttp;
      //
      LastActiveTime: TDateTime;
      Hearbeater: THeartbeatThread;
      //
      procedure SetActive(NewActive: boolean);
      procedure SetHeartbeatInterval(Interval: integer);
      procedure SetMessagePort(aPort: integer);
      procedure SetConnection(Conn: TMBConnection);
      procedure ChannelError(Sender: TObject; Socket: TSocket; const Error: string; var CanClose: boolean);
      procedure ChannelDisconnect(Sender: TObject; Socket: TSocket);
      procedure DataArrive(Sender: TObject; Socket: TSocket);
      function CutPacket(var Packet: TMBParcel): boolean;
      function RemoteExecute(InParcel: TMBParcel; OutParcel: TMBParcel): boolean;

  protected
     procedure Notification(AComponent: TComponent; Operation: TOperation); override;

   public
      Constructor Create(AOwner: TComponent); override;
      Destructor Destroy(); override;
      procedure Open;
      procedure Close;
      function BindingStrProp(const StrProp: string): boolean;
      function BindingIntProp(const IntProp: integer): boolean;
      function BindingRoleId(const RoleId: string): boolean;
      function Binding(const StrProp: string; const IntProp: integer; const RoleId: string): boolean;
      function ClearStrProp(): boolean;
      function ClearIntProp(): boolean;
      function ClearRoleId(): boolean;
      function StrPropConnectionCount(const StrProp: string): integer;
      function IntPropConnectionCount(const IntProp: integer): integer;
      function RoleIdConnectionCount(const RoleId: string): integer;
      function LastError(): string;

   published
      property Active: boolean read fActive write SetActive;
      property Connection: TMBConnection read fConnection write SetConnection;
      property HeartbeatInterval: integer read fHeartbeatInterval write SetHeartbeatInterval;
      property MessagePort: integer read fMessagePort write SetMessagePort;
      property ConnectionId: int64 read fConnectionId;
      //
      property OnChannelClosed: TChannelClosedEvent read fOnChannelClosed write fOnChannelClosed;
      property OnChannelOpened: TChannelOpenedEvent read fOnChannelOpened write fOnChannelOpened;
      property OnAllConnectionsMessage: TMessageEvent read fOnAllConnectionsMessage write fOnAllConnectionsMessage;
      property OnSingleConnectionMessage: TMessageEvent read fOnSingleConnectionMessage write fOnSingleConnectionMessage;
      property OnIntPropConnectionsMessage: TMessageEvent read fOnIntPropConnectionsMessage write fOnIntPropConnectionsMessage;
      property OnStrPropConnectionsMessage: TMessageEvent read fOnStrPropConnectionsMessage write fOnStrPropConnectionsMessage;
      property OnRoleIdConnectionsMessage: TMessageEvent read fOnRoleIdConnectionsMessage write fOnRoleIdConnectionsMessage;
      property OnCallbackMessage: TCallbackMessageEvent read fOnCallbackMessage write fOnCallbackMessage;
      property OnUnknownMessage: TUnknownMessageEvent read fOnUnknownMessage write fOnUnknownMessage;
      property OnHeartbeat: THeartbeatEvent read fOnHeartbeat write fOnHeartbeat;

   End;

主要的几个方法:
//
// 打开通道/关闭通道...
      procedure Open;
      procedure Close;
//
// 绑定属性...
      function BindingStrProp(const StrProp: string): boolean;
      function BindingIntProp(const IntProp: integer): boolean;
      function BindingRoleId(const RoleId: string): boolean;
      function Binding(const StrProp: string; const IntProp: integer; const RoleId: string): boolean;
//
// 清除绑定属性...
      function ClearStrProp(): boolean;
      function ClearIntProp(): boolean;
      function ClearRoleId(): boolean;
//
// 取绑定属性相关的连接数...
      function StrPropConnectionCount(const StrProp: string): integer;
      function IntPropConnectionCount(const IntProp: integer): integer;
      function RoleIdConnectionCount(const RoleId: string): integer;
      function LastError(): string;

主要的事件:
//
// 通道打开/关闭事件...
      fOnChannelClosed: TChannelClosedEvent;
      fOnChannelOpened: TChannelOpenedEvent;
//
// 收到群发给全部连接的事件...
      fOnAllConnectionsMessage: TMessageEvent;
//
// 收到点对点消息的事件...
      fOnSingleConnectionMessage: TMessageEvent;
//
// 收到组播给指定属性的连接的消息的事件...
      fOnIntPropConnectionsMessage: TMessageEvent;
      fOnStrPropConnectionsMessage: TMessageEvent;
      fOnRoleIdConnectionsMessage: TMessageEvent;
//
// 收到回调消息的事件...
      fOnCallbackMessage: TCallbackMessageEvent;
//
// 收到未经解释的消息事件...
      fOnUnknownMessage: TUnknownMessageEvent;
//
// 通道心跳包事件...
      fOnHeartbeat: THeartbeatEvent;


然后,结合消息发送控件,我们就可以来实现一个移动应用中的消息传输范例,设计时界面如下:
此帖子包含附件:
PNG 图像
大小:31.5K
----------------------------------------------
樵夫的大马甲
作者:
男 jopher3 (樵夫的马六甲) ▲▲▲▲▲ -
普通会员
2017/2/14 23:35:14
16楼: 功能测试代码:


//
// 清提示区...
procedure TForm1.Button1Click(Sender: TObject);
begin
   memo1.Lines.Clear;
end;

//
// 退出程序...
procedure TForm1.Button2Click(Sender: TObject);
begin
   close;
end;

//
// 连接服务器...
procedure TForm1.Button3Click(Sender: TObject);
begin
   MBConn.Host:=trim(edit1.Text);
   MBConn.Port:=strtoint(edit2.Text);
   try
      memo1.Lines.Add('');
      if MBConn.Connect then
         memo1.Lines.Add('-->连接服务器成功!')
      else
         memo1.Lines.Add('-->连接服务器失败!'+MBConn.LastError);
   except
      on e:exception do
         memo1.Lines.Add('-->连接服务器失败!'+e.ClassName+'-'+e.Message);
   end;
end;

//
// 开启/关闭接收器...
procedure TForm1.Button4Click(Sender: TObject);
begin
   memo1.Lines.Add('');
   memo1.Lines.Add('-->开始控制消息接收器...');
//
// 关闭...
   if Messager.Active then
      begin
         try
          Messager.Active:=false;
         except
          memo1.Lines.Add('*** 关闭消息接收器失败!');
         end;
      end;
//
// 开启...
   Messager.MessagePort:=strtoint(edit3.Text);
   try
      Messager.Active:=true;
   except
      memo1.Lines.Add('*** 开启消息接收器失败!');
   end;
end;

//
// 群发消息...
procedure TForm1.Button6Click(Sender: TObject);
var
   Msg: TMBParcel;
begin
   Msg:=TMBParcel.Create;
   Msg.PutStringGoods('MessageText','你们好,全部人员!');
   memo1.Lines.Add('');
   if Poster.SendToAllConnections('china',Msg) then
      memo1.Lines.Add('-->群发一个消息成功!')
   else
      memo1.Lines.Add('-->群发一个消息失败!');
   FreeAndNil(Msg);
end;

//
// 单发...
procedure TForm1.Button5Click(Sender: TObject);
var
   Msg: TMBParcel;
begin
   Msg:=TMBParcel.Create;
   Msg.PutStringGoods('MessageText','你好,我自己');
   memo1.Lines.Add('');
   if Poster.SendToConnection('china',Messager.ConnectionId,Msg) then
      memo1.Lines.Add('-->单发一个消息成功!')
   else
      memo1.Lines.Add('-->单发一个消息失败!');
   FreeAndNil(Msg);
end;

//
// 绑定属性...
procedure TForm1.Button7Click(Sender: TObject);
begin
   memo1.Lines.Add('');
   if Messager.Binding(trim(edit4.Text),strtoint(edit5.Text),trim(edit6.Text)) then
      memo1.Lines.Add('-->绑定属性到连接成功!')
   else
      begin
         memo1.Lines.Add('-->绑定属性到连接失败!');
         memo1.Lines.Add('          Error='+Messager.LastError);
      end;
end;

//
// 字串组播...
procedure TForm1.Button8Click(Sender: TObject);
var
   Msg: TMBParcel;
begin
   Msg:=TMBParcel.Create;
   Msg.PutStringGoods('MessageText','你们好,Customer');
   memo1.Lines.Add('');
   if Poster.SendToStrPropConnections('china',trim(edit4.Text),Msg) then
      memo1.Lines.Add('-->组播消息到字符属性成功!')
   else
      memo1.Lines.Add('-->组播消息到字符属性失败!');
   FreeAndNil(Msg);
end;

//
// 数值组播...
procedure TForm1.Button9Click(Sender: TObject);
var
   Msg: TMBParcel;
begin
   Msg:=TMBParcel.Create;
   Msg.PutStringGoods('MessageText','你们好,1');
   memo1.Lines.Add('');
   if Poster.SendToIntPropConnections('china',strtoint(edit5.Text),Msg) then
      memo1.Lines.Add('-->组播消息到数值属性成功!')
   else
      memo1.Lines.Add('-->组播消息到数值属性失败!');
   FreeAndNil(Msg);
end;

//
// 角色组播...
procedure TForm1.Button10Click(Sender: TObject);
var
   Msg: TMBParcel;
begin
   Msg:=TMBParcel.Create;
   Msg.PutStringGoods('MessageText','你们好,Operator');
   memo1.Lines.Add('');
   if Poster.SendToRoleIdConnections('china',trim(edit6.Text),Msg) then
      memo1.Lines.Add('-->组播消息到角色属性成功!')
   else
      memo1.Lines.Add('-->组播消息到角色属性失败!');
   FreeAndNil(Msg);
end;

//
// 收到群发消息...
procedure TForm1.MessagerAllConnectionsMessage(MsgParcel: TMBParcel; FromId: string);
var
   msg: string;
begin
   msg:=MsgParcel.GetStringGoods('MessageText');
   memo1.Lines.Add('*** 收到群发消息:'+msg);
end;

//
// 收到单发消息...
procedure TForm1.MessagerSingleConnectionMessage(MsgParcel: TMBParcel;
  FromId: string);
var
   msg: string;
begin
   msg:=MsgParcel.GetStringGoods('MessageText');
   memo1.Lines.Add('*** 收到单发消息:'+msg);
end;

//
// 收到组播给字符串属性连接的消息...
procedure TForm1.MessagerStrPropConnectionsMessage(MsgParcel: TMBParcel;
  FromId: string);
var
   msg: string;
begin
   msg:=MsgParcel.GetStringGoods('MessageText');
   memo1.Lines.Add('*** 收到字串属性组播消息:'+msg);
end;

//
// 收到组播给数值属性连接的消息...
procedure TForm1.MessagerIntPropConnectionsMessage(MsgParcel: TMBParcel;
  FromId: string);
var
   msg: string;
begin
   msg:=MsgParcel.GetStringGoods('MessageText');
   memo1.Lines.Add('*** 收到数值属性组播消息:'+msg);
end;

//
// 收到组播给角色属性连接的消息...
procedure TForm1.MessagerRoleIdConnectionsMessage(MsgParcel: TMBParcel;
  FromId: string);
var
   msg: string;
begin
   msg:=MsgParcel.GetStringGoods('MessageText');
   memo1.Lines.Add('*** 收到角色属性组播消息:'+msg);
end;

//
// 收到未知消息...
procedure TForm1.MessagerUnknownMessage(ResponseId: Integer; MsgParcel: TMBParcel);
begin
   memo1.Lines.Add('*** 收到Unknown消息!Id='+inttostr(ResponseId));
end;

//
// 通道关闭时...
procedure TForm1.MessagerChannelClosed(Sender: TObject);
begin
   memo1.Lines.Add('*** 消息接收器已关闭!');
end;

//
// 通道开启时...
procedure TForm1.MessagerChannelOpened(Sender: TObject);
begin
   memo1.Lines.Add('*** 消息接收器已开启!');
   memo1.Lines.Add('     ConnectionId='+inttostr(Messager.ConnectionId));
end;

//
// 心跳...
procedure TForm1.MessagerHeartbeat(Sender: TObject);
begin
   memo1.Lines.Add('');
   memo1.Lines.Add('--> 发送心跳包成功!');
end;

//
// BinaryRPC异步回调测试...
procedure TForm1.Button11Click(Sender: TObject);
var
   RequestParcel: TMBParcel;
begin
   RequestParcel:=TMBParcel.Create;
   RequestParcel.PutStringGoods('InputData','传入的表单数据!');
   RequestParcel.PutInt64Goods('ConnectionId',Messager.ConnectionId);
   memo1.Lines.Add('');
   if RPC.AsyncCall('/asyncplugin.asq',RequestParcel) then
      memo1.Lines.Add('--> 异步调用/asyncplugin.asq成功!等待结果...')
   else
      begin
         memo1.Lines.Add('--> 异步调用/asyncplugin.asq失败!');
         memo1.Lines.Add('       Error='+RPC.LastError);
      end;
   FreeAndNil(RequestParcel);
end;

//
// JsonRPC异步回调...
procedure TForm1.Button12Click(Sender: TObject);
var
   InputJson: TMBJson;
begin
   InputJson:=TMBJson.Create;
   InputJson.Put('InputData','传入的Json数据!');
   InputJson.Put('ConnectionId',inttostr(Messager.ConnectionId));
   memo1.Lines.Add('');
   if RPC.AsyncJsonCall('/asyncjsonplugin.asq',InputJson) then
      memo1.Lines.Add('--> 异步调用/asyncjsonplugin.asq成功!等待结果...')
   else
      begin
         memo1.Lines.Add('--> 异步调用/asyncjsonplugin.asq失败!');
         memo1.Lines.Add('       Error='+RPC.LastError);
      end;
   FreeAndNil(InputJson);
end;

//
// XML异步回调...
procedure TForm1.Button13Click(Sender: TObject);
var
   InputXML: string;
begin
   InputXML:='<?xml version="1.0"?>'+#13#10
          +'<root>'+#13#10
          +'<inputdata>传入的XML数据!</inputdata>'+#13#10
          +'<connectionid>'+inttostr(Messager.ConnectionId)+'</connectionid>'+#13#10
          +'</root>';
   memo1.Lines.Add('');
   if RPC.AsyncXMLCall('/asyncxmlplugin.asq',InputXML) then
      memo1.Lines.Add('--> 异步调用/asyncxmlplugin.asq成功!等待结果...')
   else
      begin
         memo1.Lines.Add('--> 异步调用/asyncxmlplugin.asq失败!');
         memo1.Lines.Add('       Error='+RPC.LastError);
      end;
end;

//
// 收到回调消息...
procedure TForm1.MessagerCallbackMessage(MsgParcel: TMBParcel; DllFilename: string);
var
   msg,tmpstr: string;
   j: integer;
begin
   msg:=MsgParcel.GetStringGoods('MessageText');
   memo1.Lines.Add('*** 收到回调消息:');
   memo1.Lines.Add(Msg);
   tmpstr:=dllfilename;
   j:=pos('\',tmpstr);
   while j>0 do
      begin
         delete(tmpstr,1,j);
         j:=pos('\',tmpstr);
      end;
   memo1.Lines.Add('      消息来自插件:'+tmpstr);
end;


运行效果:
此帖子包含附件:
JPEG 图像
大小:216.5K
----------------------------------------------
樵夫的大马甲
作者:
男 jopher3 (樵夫的马六甲) ▲▲▲▲▲ -
普通会员
2017/2/14 23:40:24
17楼: 正如14楼所示图那样,移动端和PC桌面之间的消息互通,就轻而易举了,下面是互通测试桌面程序截图:
此帖子包含附件:
PNG 图像
大小:11.5K
----------------------------------------------
樵夫的大马甲
作者:
男 liuzhigang (LG) ★☆☆☆☆ -
盒子活跃会员
2017/2/14 23:42:12
17楼: 2015年底 我用Indy就实现了你写的 PC 手机跨平台 长链接 单据推送到手机。打印推送
----------------------------------------------
-
作者:
男 liuzhigang (LG) ★☆☆☆☆ -
盒子活跃会员
2017/2/14 23:45:01
18楼: 只是Indy很操蛋 手机里发消息给服务端 网络异常 没有错误异常抛出 只有这个不满意 不知道你这个有这个问题不
----------------------------------------------
-
作者:
男 jopher3 (樵夫的马六甲) ▲▲▲▲▲ -
普通会员
2017/2/14 23:48:40
19楼: 这个完全脱离Indy的,不会有这个问题
----------------------------------------------
樵夫的大马甲
作者:
男 jopher3 (樵夫的马六甲) ▲▲▲▲▲ -
普通会员
2017/2/14 23:50:14
20楼: Indy封装过渡,感觉不爽,所以一直没这个耐心去深入用它。
----------------------------------------------
樵夫的大马甲
信息
登陆以后才能回复
Copyright © 2CCC.Com 盒子论坛 v3.0.1 版权所有 页面执行149.9023毫秒 RSS