1. 程式人生 > >AS3 Socket 基礎知識(很全面)

AS3 Socket 基礎知識(很全面)

解決方法: 
     對於Socket物件來說,通過是用write方法(writeByte(),writeUTFBytes( )等方法.)先向快取區寫入資料,然後使用flush()方法傳送資料.對於XMLSocket物件,使用send()方法.

討論: 
     Socket和XMLSocket類向Socket伺服器傳送資料的方法是不相同的.讓我們首先看一下Socket類的方法. 
     當你使用Socket物件向伺服器傳送資料的時候,你首先要將資料寫入到一個緩衝區中.Socket類設定了一系列的方法來寫資料.每一個方法都用於寫不 同的資料型別的資料(或者不同的資料).這些方法分別是: writeBoolean( ), writeByte( ), writeBytes( ), writeDouble( ), writeFloat( ), writeInt( ), writeMultiByte( ), writeObject( ), writeShort( ), write- UnsignedInt( ), writeUTF(), 和writeUTFBytes( ). 這些方法大多數都只接受一個引數,該引數的型別同方法的名字相匹配.例如,writeBoolean()方法接受一個布林值作為引數,而 writeByte( ), writeDouble( ), writeFloat( ), writeInt( ), writeShort( ), writeUnsignedInt( ) 方法接受一個數字型引數.writeObject()方法接受一個物件型別作為引數,但該物件必須序列化成為AMF格式.writeBytes( )方法允許你傳一個ByteArray引數,並帶有偏移量和長度兩個引數.例如,下面這段程式碼,呼叫了一個writeBytes( )方法,該方法將ByteArray物件中的所有byt值都傳出去了(偏移量為0,長度和ByteArray陣列長度等長):


socket.writeBytes(byteArray, 0, byteArray.length); 

     writeUTF( )和writeUTFBytes( ) 方法允許你的傳送字串型別的引數.每個一個方法只接受一個字串作為引數.writeUTFBytes( )方法簡單的將字串作為Bytes傳送.writeUTF( )方法在寫入真正資料之前,先寫入byts的數量.
     writeMultiByte( )方法也允許字串型別的引數,但是使用的為非預設字符集.該方法需要兩個引數:字串和字符集名稱.在Flash和Flex的幫助文件中有一個自持所有 字符集的列表,該列表中的標籤和描述符是一一對應的.使用標籤值作為writeMultiByte( )作為字符集.例如下面的程式碼傳送了一個編碼為Unicode的字串:


socket.writeMultiByte("example", "unicode"); 

     向一個Socket物件傳數值的方法完全依賴於你所有資料的型別和服務所接受資料的型別.使用一個Socket物件,你完全可以使用 ActionScript寫一個Telnet和POP mail客戶端.這兩種協議都支援ASCII字元指令.例如,在連線一個POP伺服器之後,你可以通過使用USER指令指定一個使用者.下面程式碼向一個 Socket物件發一條指令:

// POP servers expect a newline (\n) to execute the preceding command. 
socket.writeUTFBytes("USER exampleUsername\n"); 


 向一個Socket物件寫入資料其實並沒有將資料傳送到Socket伺服器.每呼叫一個write方法都向Socket物件新增一個數據.例如,下面程式碼向一個Socket物件添加了四個byte的資料,但是沒有一個發出了.

socket.writeByte(1); 
socket.writeByte(5); 
socket.writeByte(4); 
socket.writeByte(8); 

 當你想將這些累積的資料傳送到Socket伺服器需要呼叫flush()方法.flush()方法呼叫之後將把所有已經寫入的資料傳送出去,並清空緩衝區: 

socket.flush(   ); 

     XMLSocket類是一個非常簡單用於傳送資料的API.寫於發資料都是由send()這一個方法來完成的.send()方法可以接受任何資料型別的參 數.它可以將所有的引數都轉換為一個字串型別併發送到伺服器.通常引數為一個XML物件或者一個包含資料結構類似XML資料的字串:

xmlSocket.send(xml); 

     然而,準確的格式完全依賴於伺服器所能夠接受的格式.如果伺服器接受XML格式的資料,你必須傳送XML格式的資料.如果伺服器只接受URL編碼的資料,你也必須傳送URL編碼的資料.


3.從Socket伺服器讀資料 

解決方法: 
     對於Socket例項,先收到socketData事件,然後呼叫如下兩個方法的一個,比如,readByte()或者readInt(),在事件控制器中確定不會去讀過去的bytesAvailable.
     對於XMLSocket例項,先收到data事件,然後解析從事件控制器內部裝載的XML資料. 

討論: 
     從一個socket連線接收的資料依賴於你使用的Socket的型別.socket和XMLSocket都可以從伺服器接受到資料,但是它們處於不同重量級的技術.讓我們在討論XMLSocket之前先關注下Socket類.
     我都知道socket在Flash中是一個非同步的行為.因此,它就不能簡單的建立一個Socket連線,然後就立刻嘗試去讀取資料.read方法不能等到 從伺服器傳過來資料之後在返回.換句話說,你只能在客戶端從伺服器載入所有資料之後才可以讀取資料.在資料可用之前讀資料會產生一個錯誤.
     通過socketData事件廣播到Socket例項,這樣我們就可以知道什麼時候資料可以被讀取.那麼我們要為socketData事件新增一個事件監 聽器,任何時候只要有新的資料從一個socket伺服器傳送過來,都會觸發事件控制器.在事件處理器的內部我們寫入我們要執行的程式碼去讀取和處理收到的數 據.
     從一個前端伺服器讀取資料,Socket類為我們提供了許多不同的方法,這些方法依賴於你所讀得資料型別.例如,你可以通過readByte()方法讀一 個byte資料,或者通過一個使用readUnsignedInt()方法去讀一個無符號整數.下面這個表列出來能夠從伺服器讀取的資料型別,返回值,和 read方法每次讀入的位元組數.

Table:Socket read methods for various datatypes 
方法:返回值型別         描述         位元組數 
readBoolean( ):Boolean         從Socket讀取一個Boolean值.         1 
readByte( ):int         從Socket讀取一個byte值.         1 
readDouble( ):Number         從Socket讀取一個IEEE 754雙精度浮點數.         8 
readFloat( ):Number         從Socket讀取一個IEEE 754單精度浮點數.         4 
readInt( ):int         從Socket讀取一個有符號32-bit整數值.         4 
readObject( ):*         從Socket讀取一個AMF-encoded物件.         n 
readShort( ):int         從Socket讀取一個有符號16-bit整數值.         2 
readUnsignedByte( ):uint         從Socket讀取一個無符號位元組.         1 
readUnsignedInt( ):uint         從Socket讀取一個無符號32-bit整數         4 
readUnsignedShort( ):uint         從Socket讀取一個無符號16-bit整數.         2 
readUTF( ):String         從Socket讀取一個一個UTF8字串.         n 


     有兩個額外的方法沒有在上面這個表中描述.它們分別是readBytes()和readUTFBytes().readBytes()方法只可以讓socket讀資料但不能返回一個值,並且該方法需要3個引數:

bytes: 
     一個flash.util.ByteArray例項讀取從socket中收到的資料. 
offset: 
     一個uint值,指定從什麼位置開始讀取socket中收到資料的偏移量.預設值為0. 
length: 
     一個uint值,用於指定讀取bytes的數量.預設值為0,意思就是說將所有的可用的資料都放入ByteArray中. 

     另一個readUTFBytes()方法,只需要一個長度引數用於指定UTF-8位元組的讀入數量,並且該方法會將所有讀入的位元組碼轉換成為字串型別. 

注意:在從一個Socket讀資料之前,首先要判斷bytesAvailable的屬性.如果你不知道要讀入的資料型別是什麼就去讀資料的話,將會產生一個錯誤(flash.errors.EOFError).

     下面的例子程式碼連線了一個socket伺服器,讀取並顯示每次從伺服器發來的資料. 

package { 
   import flash.display.Sprite; 
   import flash.events.ProgressEvent; 
   import flash.net.Socket; 

   public class SocketExample extends Sprite { 

     private var socket:Socket; 

     public function SocketExample(   ) { 
       socket = new Socket(   ); 

       // Listen for when data is received from the socket server 
       socket.addEventListener( ProgressEvent.SOCKET_DATA, onSocketData ); 

       // Connect to the server 
       socket.connect( "localhost", 2900 ); 
     } 

     private function onSocketData( eventrogressEvent ):void { 
       trace( "Socket received " + socket.bytesAvailable + " byte(s) of data:" );

       // Loop over all of the received data, and only read a byte if there 
       // is one available 
       while ( socket.bytesAvailable ) { 
         // Read a byte from the socket and display it 
         var data:int = socket.readByte(   ); 
         trace( data ); 
       } 
     } 
   } 


     在上面的這個例子中,如果一個socket伺服器傳送回一個訊息(例如"hello"),當一個客戶段連入伺服器就會返回並輸出下面類似的文字: 

Socket received 5 byte(s) of data: 
72 
101 
108 
108 
111 

注意:一旦資料從socket讀出,它就不能再次被讀.例如,讀一個位元組之後,這個位元組就不能再"放回來",只能讀後邊的位元組. 

     當收到的資料為ASCII編碼,你可以通過readUTFBytes()方法重新構建一個字串.readUTFBytes()方法需要知道多少個位元組需要轉換為字串.你可以使用bytesAvailable去讀所有的位元組資料:

var string:String = socket.readUTFBytes(socket.bytesAvailable); 

     XMLSocket類的動作和Socket類相比在從伺服器接受資料的風格相似.兩者都是通過事件監聽器來監聽資料接收通知的,這主要取決於Flash非同步的Socket實現.然而,在處理實際資料的時候有很大的不同.

     有個XMLSocket例項在從伺服器下載完資料後分發資料事件.通過flash.events.DataEvent.DATA常量定義的資料事件包含一個data屬性,該屬性包含了從伺服器收到的資訊.

注意:使用XMLSocket從伺服器返回的資料總是認為是一個字串型別的資料.這樣不用為任何資料型別的資料指定讀取方法. 

     這些從伺服器返回的資料是沒有經過任何處理的原始資料.因此,你不能通過XMLSocket連線立即使用XML,你傳送和接收的都是純字串資料.如果你期望XML,在你處理資料之前,你必須首先將這些資料轉換為一個XML的例項.
     下面的這段程式碼在初始化的時候通過XMLSocket連線到了本地伺服器的2900埠.在連線成功之後,一個<test>訊息會發送到服務 器.onData事件監聽者控制從伺服器返回的響應.在本例中返回字串<response><test success='true'/></response>.你可以通過事件的data屬性發現為字串資料,然後XML類的建構函式將 字串轉換成為了XML例項.最後,通過使用E4X語法的XML例項的一部分資訊.(關於通過使用E4X處理XML的更多詳細資訊,我們需要另外討論.)

package { 
   import flash.display.Sprite; 
   import flash.events.Event; 
   import flash.events.DataEvent; 
   import flash.net.XMLSocket; 

   public class SocketExample extends Sprite { 

     private var xmlSocket:XMLSocket; 

     public function SocketExample(   ) { 
       xmlSocket = new XMLSocket(   ); 

       // Connect listener to send a message to the server 
       // after we make a successful connection 
       xmlSocket.addEventListener( Event.CONNECT, onConnect ); 

       // Listen for when data is received from the socket server 
       xmlSocket.addEventListener( DataEvent.DATA, onData ); 

       // Connect to the server 
       xmlSocket.connect( "localhost", 2900 ); 
     } 

     private function onConnect( event:Event ):void { 
       xmlSocket.send( "<test/>" ); 
     } 

     private function onData( eventataEvent ):void { 
       // The raw string returned from the server. 
       // It might look something like this: 
       // <response><test success='true'/></response> 
       trace( event.data ); 

       // Convert the string into XML     
       var response:XML = new XML( event.data ); 

       // Using E4X, access the success attribute of the "test" 
       // element node in the response. 
       // Output: true 
       trace( [email protected] ); 
     } 
   } 


注意:在data事件分發資料之前,XMLSocket例項必須從伺服器收到一個表示為空的byte('\\0').也就是說,從伺服器僅僅只傳送所需要的字串是不夠的,必須在結尾處加入一個表示為空的byte.