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又是滿的。 附一下代碼進行研究: view plaincopy to clipboardprint? 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); //對解碼后的數據進行處理,可以說是直接使用、賦值 } } 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 view plaincopy to clipboardprint? package org.green.server.data { import flash.utils.ByteArray; public class PacketBuffer { private var buf:ByteArray = new ByteArray(); private static const SPLIT:int = 21316;// "DS" public function PacketBuffer() { } public function push(ba:ByteArray):void { if(buf == null) { buf = ba; }else { buf.position = buf.length; buf.writeBytes(ba); } } public function getPackets():Array { var ps:Array = []; var ptr:uint = 0; buf.position = ptr; while(buf.bytesAvailable >= 2) //這里是說當可用數據大於包頭時,一個包==包頭(body的長度)+包體(body),也就是說包里如果一旦有數據就開始執行 { //2其實是readShort()后,少了的2個字節,也就是body有數據的時候才開始解碼 var len:uint = buf.readShort(); //不足一個包,這里完全有可能,當只讀取完包頭len,但是body卻沒有讀取到末尾 if(buf.bytesAvailable < len) { var ba:ByteArray = MsgUtil.createByteArray(); buf.position = ptr; ba.writeBytes(buf, 0, buf.bytesAvailable); buf = ba; //返回 return ps; } buf.position = 2; var mb:ByteArray = new ByteArray(); buf.readBytes(mb, 0, len); //len為body的長度,將body的數據放入mb mb.position = 0; var msg:MsgPacket = MsgUtil.createMsgPacket(mb,magic);//這里在對body解碼過程 略 buf.position=0; ps.push(msg); //放入數組 //下一個包 while語句進行下一個循環 } if(buf.bytesAvailable <= 0)buf = null; return ps; } public function clear():void { buf=null; } } } 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); } } }