博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Beetle使用FluorineFx和Flash进行AMF3通讯
阅读量:5829 次
发布时间:2019-06-18

本文共 8840 字,大约阅读时间需要 29 分钟。

    之前的文章已经介绍了Beetle使用ProtoBuf.net进行对象序列化数据传输,这一章主要讲述Beetle如何使用FluorineFx和Flash进行AMF3通讯.其实现原理和使用ProtoBuf.net一样,扩展出一个MessageAdapter即可以.

    MessageAdapter的实现如下:

public  class MessageAdapter:IMessage    {        public object Message        {            get;            set;        }        public static bool Send(TcpChannel channel,object message )        {            MessageAdapter ma = new MessageAdapter();            ma.Message = message;            return channel.Send(ma);        }        public void Load(BufferReader reader)        {            ByteArraySegment segment = ArrayPool.Pop();            int count = reader.ReadInt32();            reader.Read(count - 4, segment);            using (System.IO.MemoryStream steram = new System.IO.MemoryStream(segment.Array, segment.Offset, segment.Count))            {                FluorineFx.AMF3.ByteArray ba = new FluorineFx.AMF3.ByteArray(steram);                ba.ObjectEncoding = FluorineFx.ObjectEncoding.AMF3;                Message = ba.ReadObject();            }            ArrayPool.Push(segment);        }        public void Save(BufferWriter writer)        {            ByteArraySegment segment = ArrayPool.Pop();            using (System.IO.MemoryStream steram = new System.IO.MemoryStream(segment.Array))            {                FluorineFx.AMF3.ByteArray ba = new FluorineFx.AMF3.ByteArray(steram);                ba.ObjectEncoding = FluorineFx.ObjectEncoding.AMF3;                ba.WriteObject(Message);                segment.SetInfo(0, (int)steram.Position);            }            writer.Write(segment.Count + 4);            writer.Write(segment.Array,segment.Offset,segment.Count);            ArrayPool.Push(segment);        }        public static ByteArrayPool ArrayPool = new ByteArrayPool(200, 1024 * 8);    }

     消息适配器实现比较简单在对象写入流的时候先把AMF3序列化对象流的长度+4写入头4个字节,然后再写入AMF3的数据流内容,从流中读取对象原来一样先把消息长度读取出来然后再读取AMF3数据流然后反序列化对象即可.

     实现一个消息头描述长度的协议分析器:

public class HeadSizePackage:HeadSizeOfPackage    {        public HeadSizePackage()        {        }        public HeadSizePackage(TcpChannel channel)            : base(channel)        {        }        protected override IMessage ReadMessageByType(BufferReader reader, out object typeTag)        {            typeTag = "MessageAdapter";            return new MessageAdapter();        }        protected override void WriteMessageType(IMessage msg, BufferWriter writer)        {                    }        public override void MessageWrite(IMessage msg, BufferWriter writer)        {            msg.Save(writer);        }        public override IMessage MessageRead(BufferReader reader)        {            IMessage msg = null;            object typeTag;            msg = ReadMessageByType(reader, out typeTag);            if (msg == null)                throw NetTcpException.TypeNotFound(typeTag.ToString());            try            {                msg.Load(reader);            }            catch (Exception e)            {                NetTcpException err = NetTcpException.ObjectLoadError(typeTag.ToString(), e);                throw err;            }            return msg;        }    }

     这样一个消息扩展就完成具体生成的协议格式如下:

    协议制定后就可似使用Beetle搭建基于AMF3的.net和flash数据传输。

首先是制定一个Tcp服务

TcpUtils.Setup(200, 1, 1);            TcpServer server = new TcpServer();            server.ChannelConnected += OnConnected;            server.ChannelDisposed += OnDisposed;            server.Open(8340);

    以上代码很简单初始化组件信息,构建一个TcpServer并绑定连接接入事件和连接断开事件;然后在所有IP的8340端绑定tcp服务。在连接接入的时候我们需要做些事情。

static void OnConnected(object sender, ChannelEventArgs e)        {            e.Channel.SetPackage
().ReceiveMessage = OnMessageReceive; e.Channel.ChannelError += OnError; e.Channel.BeginReceive(); Console.WriteLine("{0} connected!", e.Channel.EndPoint); }

    在接入的事件里针对当前的Tcp通道设置一个协议分包器,并指定对应接收消息事件;Tcp通道相关信息设置完成后就可以调用BeginReceive()方法进入数据接收状态。接下来是消息处理事件的代码:

static void OnMessageReceive(PacketRecieveMessagerArgs e)        {            Beetle.FluorineFxAdapter.MessageAdapter adapter = (Beetle.FluorineFxAdapter.MessageAdapter)e.Message;            if (adapter.Message is AMF3.Messages.Register)            {                OnRegister((AMF3.Messages.Register)adapter.Message,e.Channel);            }            else if (adapter.Message is AMF3.Messages.Get)            {                OnGet((AMF3.Messages.Get)adapter.Message, e.Channel);            }            else            {            }                    }        static void OnRegister(AMF3.Messages.Register e, TcpChannel channel)        {            Console.WriteLine("{0} Register\t UserName:{1};PWD:{2};EMail:{3}", channel.EndPoint, e.UserName, e.PWD, e.EMail);        }        static void OnGet(AMF3.Messages.Get e, TcpChannel channel)        {            Console.WriteLine("{0} Get \t Customer:{1}", channel.EndPoint, e.CustomerID);            AMF3.Messages.GetResponse response = new Messages.GetResponse();            for (int i = 0; i < 10; i++)            {                AMF3.Messages.Order order = new Messages.Order();                order.OrderID = 10248;                order.CustomerID = "WILMK";                order.EmployeeID = 5;                order.OrderDate = 629720352000000000;                order.RequiredDate = 629744544000000000;                order.ShipAddress = "59 rue de l'Abbaye";                order.ShipCity = "Reims";                order.ShipCountry = "France";                order.ShipName = "Vins et alcools Chevalier";                order.ShipPostalCode = "51100";                order.ShipRegion = "RJ";                response.Items.Add(order);            }            Beetle.FluorineFxAdapter.MessageAdapter.Send(channel, response);        }

    在这个例子中只处理了两种消息对象,分别是Register和Get;接收到Register只做了一个简单的输出,而在接收到Get则会返回一个Order列表。

Flash端实现

    首先要实现协议分包器,由于Flash提供的Socket方法挺方便所以实现起来也是很容易的事情.

package{	import flash.net.Socket;	import flash.utils.ByteArray;	import flash.utils.Endian;		import mx.graphics.shaderClasses.ExclusionShader;	public  class HeadSizeOfPackage	{		public function HeadSizeOfPackage()		{		}		private var mMessageReceive:Function;		//消息接收回调函数		public function get MessageReceive():Function		{			return mMessageReceive;		}		public function set MessageReceive(value:Function):void		{			mMessageReceive = value;		}		private var mReader:ByteArray = new ByteArray();		private var mWriter:ByteArray = new ByteArray();		private var mSize:int=0;		//导入当前Socket接收的数据		public function Import(socket:Socket):void		{			socket.endian = Endian.LITTLE_ENDIAN;			while(socket.bytesAvailable>0)			{				if(mSize==0)				{					mSize= socket.readInt()-4;					mReader.clear();				}				if(socket.bytesAvailable>= mSize)				{					socket.readBytes(mReader,mReader.length,mSize);					var msg:Object = mReader.readObject();					if(MessageReceive!=null)						MessageReceive(msg);					mSize=0;				}				else{					mSize= mSize-socket.bytesAvailable;					socket.readBytes(mReader,mReader.length,socket.bytesAvailable);				}			}		}		//发磅封装的协议数据		public function Send(message:Object,socket:Socket):void		{			socket.endian = Endian.LITTLE_ENDIAN;			mWriter.clear();			mWriter.writeObject(message);			socket.writeInt(mWriter.length+4);			socket.writeBytes(mWriter,0,mWriter.length);			socket.flush();		}	}}

    如果需要读取的数据大小为零则表明是一个新的消息,这个时候先把消息大小读取出来,注意由于c#是低字序,beetle的实现也没有处理.所以在这里需要把flash的socket设置成低字序处理.当读取一个完整的AMF3数据流后就直接读取相关对象并通过函数回调.在发送消息的方法原理一样,先写入消息总长度然后写入对应的AMF3数据流即可.这样一个flash端的分包和封包器就完成,下面就可以接入到.net的服务端进行数据交互了.

private var mPackage:HeadSizeOfPackage = new HeadSizeOfPackage();			protected function cmdConnect_clickHandler(event:MouseEvent):void			{				// TODO Auto-generated method stub				mSocket = new Socket();				mSocket.connect(txtIPAddress.text,9860);				mSocket.addEventListener(Event.CONNECT,onConnected);				mSocket.addEventListener(ProgressEvent.SOCKET_DATA,socketDataHandler);				mSocket.endian = Endian.LITTLE_ENDIAN;				mPackage.MessageReceive=OnReceive;							}			private function OnReceive(msg:Object):void			{				if(msg is GetResponse)				{					var response:GetResponse=  GetResponse(msg);					lstData.dataProvider=new ArrayCollection(response.Items);				}			}			private function socketDataHandler(event:ProgressEvent):void {				trace("socketDataHandler: " + event);				mPackage.Import(mSocket);							}			private function onConnected(event:Event):void			{				cmdRegister.enabled= true;				cmdGet.enabled = true;			}						protected function cmdRegister_clickHandler(event:MouseEvent):void			{				// TODO Auto-generated method stub				var reg:Register = new Register();				reg.EMail = txtEMail.text;				reg.UserName=txtUserName.text;				reg.PWD = txtPWD.text;				mPackage.Send(reg,mSocket);			}						protected function cmdGet_clickHandler(event:MouseEvent):void			{				// TODO Auto-generated method stub				var get:Get = new Get();				get.CustomerID = txtCustomerID.text;				mPackage.Send(get,mSocket);			}

    具体运行效果

转载地址:http://quodx.baihongyu.com/

你可能感兴趣的文章
python面向对象基础
查看>>
HDU 2044 一只小蜜蜂(递归)
查看>>
docker 下 安装rancher 笔记
查看>>
spring两大核心对象IOC和AOP(新手理解)
查看>>
数据分析相关
查看>>
Python LDAP中的时间戳转换为Linux下时间
查看>>
微信小程序蓝牙连接小票打印机
查看>>
环境错误2
查看>>
C++_了解虚函数的概念
查看>>
全新jmeter视频已经上架
查看>>
Windows 8下如何删除无线配置文件
查看>>
oracle系列(五)高级DBA必知的Oracle的备份与恢复(全录收集)
查看>>
hp 服务器通过串口重定向功能的使用
查看>>
国外10大IT网站和博客网站
查看>>
android第十一期 - SmoothSwitchLibrary仿IOS切换Activity动画效果
查看>>
zabbix 批量web url监控
查看>>
MongoDB CookBook读书笔记之导入导出
查看>>
shell如何快速锁定所有账号
查看>>
HTML 5实现的手机摇一摇
查看>>
Linux 文件IO理解
查看>>