导航:
论坛 -> 文档资料
斑竹:liumazi,ruralboy
作者:
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;
此帖子包含附件: 大小: 21.1K
----------------------------------------------
樵夫的大马甲
作者:
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.
此帖子包含附件: 大小: 6.8K
----------------------------------------------
樵夫的大马甲
作者:
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.
此帖子包含附件: 大小: 161.4K
----------------------------------------------
樵夫的大马甲
作者:
2017/1/22 12:46:58
3楼:
四、结束语 通过测试,我们发现这种方法完全支持跨平台及长连接,异步效果也不错! 在此,为EMB公司点个赞! 非常给力! 然后,我们在TMBSocket基础上,实现真正的即时通信、结合Service实现手机消息推送等,就变得轻而易举的了。杠杆给你了,撬地球吧!
----------------------------------------------
樵夫的大马甲
作者:
zhipu (zhipu)
★☆☆☆☆
-
普通会员
2017/1/22 13:08:19
4楼:
delphi牛人!
----------------------------------------------
-
作者:
2017/1/22 15:19:40
5楼:
膜拜大神。
----------------------------------------------
-
作者:
2017/1/22 22:23:16
6楼:
牛逼~ 一直没有钱买你的框架,好痛苦
----------------------------------------------
-
作者:
2017/1/23 8:14:31
7楼:
楼上的,年底促销,抓住机会呀! 企业版5折,只要3.98K OEM版4折,只要4.98K 一次购买永久使用、无项目数限制、升级免费 另外还送春节源码礼包、送上咱的一份实惠祝福!
----------------------------------------------
樵夫的大马甲
作者:
2017/1/23 9:10:09
8楼:
高人,能不能介绍详细一点,也便于推广
----------------------------------------------
-
作者:
2017/1/24 6:55:19
10楼:
顶一个,支持正版!
----------------------------------------------
樵夫的大马甲
作者:
2017/1/25 9:38:55
11楼:
我现在用的DIOCP,支持移动端
----------------------------------------------
18114532@qq.com
作者:
2017/1/29 14:46:26
12楼:
服务器接收巨量的并发 我使用linux+php+swoole解决方案。 简单快速高效 并发量大 稳定
----------------------------------------------
Nothing
作者:
2017/1/31 11:21:23
13楼:
支持,顶一个。
----------------------------------------------
喜欢Delphi,关注Delphi,愿和广大爱好者交朋友。
作者:
2017/2/14 23:23:27
14楼:
基于此控件,本人已经为咱的QuickBurro中间件实现了一个新的长连接异步消息通信控件:TMBMessager。终于可以不再使用HTTP轮询来实现敏捷的消息通信了,实时、快速、支持较大并发、异步事件驱动、支持分组等等。 下面是此消息传输体系的示意图:
此帖子包含附件: 大小: 128.3K
----------------------------------------------
樵夫的大马甲
作者:
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; 然后,结合消息发送控件,我们就可以来实现一个移动应用中的消息传输范例,设计时界面如下:
此帖子包含附件: 大小: 31.5K
----------------------------------------------
樵夫的大马甲
作者:
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; 运行效果:
此帖子包含附件: 大小: 216.5K
----------------------------------------------
樵夫的大马甲
作者:
2017/2/14 23:40:24
17楼:
正如14楼所示图那样,移动端和PC桌面之间的消息互通,就轻而易举了,下面是互通测试桌面程序截图:
此帖子包含附件: 大小: 11.5K
----------------------------------------------
樵夫的大马甲
作者:
2017/2/14 23:42:12
17楼:
2015年底 我用Indy就实现了你写的 PC 手机跨平台 长链接 单据推送到手机。打印推送
----------------------------------------------
-
作者:
2017/2/14 23:45:01
18楼:
只是Indy很操蛋 手机里发消息给服务端 网络异常 没有错误异常抛出 只有这个不满意 不知道你这个有这个问题不
----------------------------------------------
-
作者:
2017/2/14 23:48:40
19楼:
这个完全脱离Indy的,不会有这个问题
----------------------------------------------
樵夫的大马甲
作者:
2017/2/14 23:50:14
20楼:
Indy封装过渡,感觉不爽,所以一直没这个耐心去深入用它。
----------------------------------------------
樵夫的大马甲