Socket+AMF3粘包问题

服务端Mina 前台接收Flex   
参照的原型为http://www.klstudio.com/post/202.html
<[Socket+AMF3]给合Flash的Socket和AMF3来尝试开发web游戏>
经过个人调试  分别在服务端和客户端收发消息时进行长度处理
但是在服务端大量发送数据时,还是会发生客户端粘包的状况,导致发生错误,而且也比较频繁。
求服务端与客户端的收发代码段。要实用的。
(最好是经过一定压力测试的。或者发上来我压一下。)

补充说明一次我打断点跟踪到的情况:
客户端接收到信息:
获取了长度:长度为34字节   查看socket里面也确实还有34字节的内容
但是这时候就读取object就会出现异常
flex.messaging.io.UnknownTypeException: Unknown AMF type '120'
120这个就是34字节当中的第一个的内容  还有其他的比如 -124 之类的等等。

 

这个基本是socket编程都会遇到的经典问题

amf本身是一种2进制封装,连发时接收方可能会因为数据堆积在一起而分不清包的头尾,造成映射错误。

解决办法就是在发包前对amf进行简单封包,因为amf本身就是2进制格式,那么只需要在其之前写入amf长度(即正文长度),接收方,先读取包头的长度,再固定取出其后的正文。取完正文,再取包头,依次取完。

每个发出的包,结构为

  1. struct
  2. {
  3.      DWORD  Data_LEN     //包长
  4.    CHAR[..]     //内容
  5. }
复制代码

理论说完,就给出关键代码,相信认真研究过socket的一看就知:

as3  --->  Server    发送部分

  1. public function send(obj:Object)
  2. {   
  3.    var objByte:ByteArray = new ByteArray();
  4.    objByte.writeObject(obj);
  5.    // objByte.compress();   //压缩,可以省略
  6.   var msgByte:ByteArray = new ByteArray();
  7.    msgByte.writeInt(objByte.length);
  8.    msgByte.writeBytes(objByte, 0, objByte.length);

  9.    sk.writeBytes(msgByte);
  10.    sk.flush();   
  11. }
复制代码

server --> as3  接收部分

  1. //一接受到数据就尝试读
  2. private function onSkData(e:ProgressEvent):void
  3. {
  4.    this.readData();
  5. }
  6. private function readData():void
  7. {     
  8. //如果还没读过头部则读一次。
  9. if (!this.isReadHead && this.sk.bytesAvailable > 4)
  10. {
  11.   var lenByte:ByteArray = new ByteArray();
  12.   sk.readBytes(lenByte, 0, 4);
  13.   this.msgLen = lenByte.readInt();
  14.   //trace("新的消息长度:" + this.msgLen);
  15.   this.isReadHead = true;
  16. }
  17. //如果读了头部,并且当前可读长度大于等于消息长度,则开始读取
  18. if (isReadHead && this.sk.bytesAvailable >= this.msgLen)
  19.   {
  20.   var objByte:ByteArray = new ByteArray();
  21.   sk.readBytes(objByte, 0, this.msgLen);
  22.   this.isReadHead = false;
  23.   //objByte.uncompress();
  24.   var obj:Object = objByte.readObject();
  25.   this.readMsg(obj);   //读完了,可以去解释了
  26.   }
  27. //如果是读过头,则如果当前消息大于消息长度则再次调用读取,否则则判断是否可读头部
  28.   this.sk.bytesAvailable > 0 && this.readData();
  29.          
  30. }  
复制代码

至于server端,其原理是一样的,都是读的时候先读头,发的时候也是先发个头。

晚上回去再补充一下

-----------

补充server端代码(C#,解码类为FluorineFx,仅供参考思路)

server -> as3 发送

  1. public void send(object obj)
  2.         {
  3.             try
  4.             {
  5.                 ByteArray objByte = new ByteArray();
  6.                 objByte.WriteObject(obj);
  7.                // objByte.Compress();
  8.                 byte[] objBuff = new byte[objByte.Length];
  9.                 objByte.Position = 0;
  10.                 objByte.ReadBytes(objBuff, (uint)0, (uint)objBuff.Length);
  11.               
  12.                 ByteArray msgByte = new ByteArray();
  13.                 msgByte.WriteInt(objBuff.Length);
  14.                 msgByte.WriteBytes(objBuff, 0, objBuff.Length);
  15.                 byte[] msgBuff = new byte[msgByte.Length];
  16.                 msgByte.Position = 0;
  17.                 msgByte.ReadBytes(msgBuff, (uint)0, (uint)msgBuff.Length);
  18.                 //发送
  19.                 this.ng.sk.BeginSend(msgBuff, 0, msgBuff.Length, SocketFlags.None, onSendOver, this.ng);
  20.   
  21.             }
  22.             catch
  23.             {
  24.                 Core.mainForm.addLog("发送失败");
  25.             }
  26.         }
复制代码

as3 -> server 接受

  1.    
  2. //接收完的回调
  3.        private void receOver(IAsyncResult ar)
  4.         {
  5.                 NetGate ng = (NetGate)ar.AsyncState;
  6.                 int size = ng.sk.EndReceive(ar);
  7.                // Core.mainForm.addLog("接受到总长度:" + size);
  8.                 int ind = 0;
  9.                 if (size > 0)
  10.                 {
  11.                     while (size > 0)
  12.                     {
  13.                         //读消息头
  14.                         MemoryStream lenMs = new MemoryStream(ng.buff, ind, 4);
  15.                         ByteArray lenByte = new ByteArray(lenMs);
  16.                         Int32 len = lenByte.ReadInt();
  17.                        // Core.mainForm.addLog("消息长度:" + len.ToString());
  18.                         if (len == 0) { break; }
  19.                         //根据头长度取内容
  20.                         MemoryStream ms = new MemoryStream(ng.buff, ind + 4, len);
  21.                         ByteArray ba = new ByteArray(ms);
  22.                        // ba.Uncompress();
  23.                         object obj = ba.ReadObject();
  24.                         this.readMsg(obj);
  25.                         ind += (len + 4);
  26.                         size -= (len + 4);
  27.                     }
  28.                     this.ng.buff.Initialize();
  29.                     ng.sk.BeginReceive(this.ng.buff, 0, this.ng.buffSize, SocketFlags.None, this.onReceOver, this.ng);
  30.                 }
  31.                 else
  32.                 {
  33.                     ng.sk.Close();
  34.                     this.offLine();
  35.                 }
  36.         }
复制代码

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值