Beetle在TCP通讯中使用AMF3协议和Flash通讯

Flash是现有网页中最流行的富客户端表现软件,所以组件支持Flash对象协议通讯也是非常有必要的事情.由于组件可以通过扩展协议分析器来兼容不同协议处理,所以可以通过使用FluorineFx就可以简单地实现基于AMF3的协议和Flash进行TCP通讯.如果有了解之前的Protobuf的扩展,那扩展AMF3也是很简单的事情.

定义协议格式

同样在交互前要明确一下协议的格式先,只有这样才可以方便的进行代码编写实现.

协议比较简分别消息总长度和内容,内容即是AMF3协议数据.

实现具体的分析器和消息适配器

协议制定后就可以进行分析器的实现,采用头4字节描述大小,所以分析器从HeadSizeOfPackage基础类派生下载重写相关方法即可;完整实现代码如下:

    public class AMF3Package:HeadSizeOfPackage
    {
        public AMF3Package()
        {
        }
        public AMF3Package(TcpChannel channel)
            : base(channel)
        {
        }
        public override object ReadCast(object message)
        {
            return ((MessageAdapter)message).Message;
        }

        public override object WriteCast(object message)
        {
            MessageAdapter adapter = new MessageAdapter();
            adapter.Message = message;
            return adapter;
        }

        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;
        }

        class MessageAdapter : IMessage
        {
            public object Message
            {
                get;
                set;
            }

            public void Load(BufferReader reader)
            {
                ByteArraySegment segment = ByteSegment;
                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();
                }
                
            }
            public void Save(BufferWriter writer)
            {
                ByteArraySegment segment = ByteSegment;
                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);
               
            }
            [ThreadStatic]
            private static ByteArraySegment mByteSegment;
            public static ByteArraySegment ByteSegment
            {
                get
                {
                    if (mByteSegment == null)
                        mByteSegment = new ByteArraySegment(TcpUtils.DataPacketMaxLength);
                    return mByteSegment;
                }
            }
        }
    }

Flash端协议分析器

package
{
	import flash.net.Socket;
	import flash.utils.ByteArray;
	import flash.utils.Endian;
	
	import mx.controls.Alert;
	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();
		}
	}
}

运行效果

由于服务端的实现和之前的一样并没有什么改变只是更换一下泛型参,因此不再讲述具体实现了.以下是运行效果图.

下载代码:Code

总结

组件通过使用FluorineFx就可以简单实现和Flash进行AMF3的通讯,FluorineFx对AMF3的支持不错,不过应该组件似乎已经很久没有更新,在看他的源码时发现其性能还有很大的优化空间.如果使用FluorineFx的朋友对他的性能不感不理想,可以通过内存分析工具来分析一下大体可以找到慢的一些原因.

posted @ 2012-10-23 22:27  beetlex  阅读(2216)  评论(2编辑  收藏  举报