AS3: Socket 数据包 收 发

 

AS3: Socket 数据包 收 发  

2011-02-17 10:22:24|  分类: 邻里妙文 |  标签: |字号 订阅

AS3.0中使用Socket使用tcp服务器协议,它是一种流协议,不停的将分片传输给客户端,P作为流,发包是不会整包到达的,而是源源不断的。

它不同于UDP服务器协议,UDP作为数据包协议,整包到达。   

  

如果要使用Socket接收数据我们必须使用ProgressEvent.SOCKET_DATA事件。这个事件在帮助文档中是这样描述的 ——在套接字接收到数据后调度。
而事实却并非如此,做过一次尝试,服务器发送了20000次数据而rogressEvent.SOCKET_DATA事件只产生了2000多次。
那么为什么说"服务器发送了20000次数据而rogressEvent.SOCKET_DATA事件只产生了2000多次",
因为flash socket使用的TCP/IP协议, 这个协议跟UDP不同,它不是以单个"包"的形式发送数据,它发送的是"流数据",所以即便你发来20000次数据(也就是你所想象的20000个包),TCP协议也是将它视作"流"发送.
换句话说,你的20000次数据,实际上只被分割成了2000多个"包"来发送,因此socket收到了2000多个包,,因此只产生了2000多次的事件.

     另外,如果as3 的data事件函数正在执行的时候,比如在此函数中用while循环解码,此时有新的数据发送过来,data事件还会触发么?触发的话,正在执行的怎么办?原有数据还有么?

答案是会触发的,所以将socket数据read的时候,必须做一个循环 while,每到一个包刚好读取完成的时候(包头用一个整型记录完整包的长度。每次都先读取一个包长度,然后按照包长度读取指定长度的数据作为一个完整数 据包传递到到逻辑层),又继续读取下一个包,然后把解码后的每个包都放进一个数组里面依次读取。还有一点要注意的是 socket.bytesAvailable长度是每read一次就减去所读的长度,直至读取完毕,最后为0;此处的bytesAvailable如果重 新设置position为0,那该数组的bytesAvailable又是满的。

附一下代码进行研究:

  1. private function Net_Data(evt:ProgressEvent):void  
  2.   {  
  3.        var ba:ByteArray = new ByteArray();//创建一个  
  4.        socket.readBytes(ba, 0, evt.bytesTotal);  //服务器一次性发送的总共的数据,可能是几个包,也可能是几个半包  
  5.        packetBuffer.push(ba);   //把ba放入缓冲区,其实就是把ba放入packetBuffer类中的一个ByteArray对象里  
  6.        var packets:Array = packetBuffer.getPackets();  //这里就是在进行解码(包含循环)  
  7.        for each(var packet:MsgPacket in packets)  
  8.        {  
  9.         dispatch(packet);  //对解码后的数据进行处理,可以说是直接使用、赋值  
  10.        }  
  11.   }  
private function Net_Data(evt:ProgressEvent):void { var ba:ByteArray = new ByteArray();//创建一个 socket.readBytes(ba, 0, evt.bytesTotal); //服务器一次性发送的总共的数据,可能是几个包,也可能是几个半包 packetBuffer.push(ba); //把ba放入缓冲区,其实就是把ba放入packetBuffer类中的一个ByteArray对象里 var packets:Array = packetBuffer.getPackets(); //这里就是在进行解码(包含循环) for each(var packet:MsgPacket in packets) { dispatch(packet); //对解码后的数据进行处理,可以说是直接使用、赋值 } }


packetBuffer.as

  1.   package org.green.server.data  
  2. {  
  3.     import flash.utils.ByteArray;  
  4.       
  5.     public class PacketBuffer  
  6.     {  
  7.         private var buf:ByteArray = new ByteArray();  
  8.         private static const SPLIT:int = 21316;// "DS"  
  9.         public function PacketBuffer()  
  10.         {  
  11.         }  
  12.         public function push(ba:ByteArray):void  
  13.         {  
  14.             if(buf == null)  
  15.             {  
  16.                 buf = ba;  
  17.             }else  
  18.             {  
  19.                 buf.position = buf.length;  
  20.                 buf.writeBytes(ba);  
  21.             }  
  22.         }  
  23.         public function getPackets():Array  
  24.         {  
  25.             var ps:Array = [];  
  26.             var ptr:uint = 0;  
  27.             buf.position = ptr;  
  28.             while(buf.bytesAvailable >= 2)  //这里是说当可用数据大于包头时,一个包==包头(body的长度)+包体(body),也就是说包里如果一旦有数据就开始执行  
  29.             {                                //2其实是readShort()后,少了的2个字节,也就是body有数据的时候才开始解码  
  30.                 var len:uint = buf.readShort();  
  31.                 //不足一个包,这里完全有可能,当只读取完包头len,但是body却没有读取到末尾  
  32.                 if(buf.bytesAvailable < len)  
  33.                 {  
  34.                     var ba:ByteArray = MsgUtil.createByteArray();  
  35.                     buf.position = ptr;  
  36.                     ba.writeBytes(buf, 0, buf.bytesAvailable);            
  37.                     buf = ba;         
  38.                     //返回  
  39.                     return ps;  
  40.                 }  
  41.                 buf.position = 2;  
  42.                 var mb:ByteArray = new ByteArray();  
  43.                 buf.readBytes(mb, 0, len);   //len为body的长度,将body的数据放入mb  
  44.                 mb.position = 0;  
  45.                 var msg:MsgPacket = MsgUtil.createMsgPacket(mb,magic);//这里在对body解码过程 略  
  46.                 buf.position=0;  
  47.                 ps.push(msg);  //放入数组  
  48.                 //下一个包  while语句进行下一个循环  
  49.             }  
  50.             if(buf.bytesAvailable <= 0)buf = null;  
  51.             return ps;  
  52.         }  
  53.         public function clear():void  
  54.         {  
  55.             buf=null;  
  56.         }  
  57.     }  


原文地址:http://blog.csdn.net/a7719665/archive/2010/06/25/5694549.aspx

另附:
as3 socket test
package {
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.IOErrorEvent;
    import flash.events.ProgressEvent;
    import flash.external.ExternalInterface;
    import flash.net.Socket;
    public class receiveData extends Sprite
    {
        public function receiveData()
        {
           trace(ProgressEvent.SOCKET_DATA);
           socket.connect("127.0.0.1", 4300);
           socket.addEventListener(ProgressEvent.SOCKET_DATA, onServerData,false,0,true);
           socket.addEventListener(Event.CONNECT, connectHandler);
           socket.addEventListener(Event.CLOSE, closeHandler);
           socket.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
        }
        private var socket:Socket=new Socket();
        private var msg:String = "";
        private function onServerData(event:ProgressEvent):void{
            if(socket.bytesAvailable){
                msg = socket.readUTFBytes(socket.bytesAvailable);
                trace(msg);
                ExternalInterface.call("window.jsFunc", msg);
            }
        }
        private function connectHandler(event:Event):void{
           trace("connected");
        }
        private function closeHandler(event:Event):void{
           trace("closed");
            clearHandler();
        }
        private function ioErrorHandler(event:IOErrorEvent):void{
           //to do
           clearHandler();
        }
        private function clearHandler():void{
            socket.removeEventListener(ProgressEvent.SOCKET_DATA, connectHandler);
            socket.removeEventListener(Event.CONNECT, connectHandler);
            socket.removeEventListener(Event.CLOSE, closeHandler);
            socket.removeEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
        }
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值