Previous Page
Next Page

Recipe 24.3. Receiving Data

Problem

You want to read data from a socket server.

Solution

For Socket instances, subscribe to the socketData event and invoke one of the read methods, such as readByte( ) or readInt( ), in the event handler, making sure not to read past bytesAvailable.

For XMLSocket instances, subscribe to the data event and interpret the XML data received inside of the event handler.

Discussion

Receiving data from a socket connection depends on the type of socket you use. Both Socket and XMLSocket are capable of receiving data from a server, but they do so using slightly different techniques. Let's focus on how the Socket class works first before discussing XMLSocket.

As you've learned in the introduction to this chapter, sockets in Flash behave asynchronously. Therefore, it's not possible to simply create a socket connection and attempt to read data from the socket right away. The read methods don't wait for data to be transferred from the server before returning. Instead, you can only read data from a socket after the client has already downloaded the data from the host server. It is an error to try and read data from a Socket before any data is available.

To know when data is available to be read, the socketData event is broadcasted from Socket instances. By adding an event listener for the socketData event, your event handler is invoked anytime there is new data received from the socket server. Inside the event handler is where you write code to read and interpret the received data.

To read the data sent from the server, the Socket class provides a number of different read methods, depending on the type of data you want to read. For instance, you can read a byte with the readByte( ) method, or read an unsigned integer with the readUnsignedInt( ) method. See Table 24-1 for a list of the different datatypes that can be read from the socket server, what the return value is, and how many bytes the read method consumes.

Table 24-1. Socket read methods for various datatypes
Method : Return type Description Bytes read
                              readBoolean(  ):Boolean

Reads a Boolean value from the socket 1
                              readByte(  ):int

Reads a signed byte from the socket 1
                              readDouble(  ):Number

Reads an IEEE 754 double-precision floating-point number from the socket 8
                              readFloat(  ):Number

Reads an IEEE 754 single-precision floating-point number from the socket 4
                              readInt(  ):int

Reads a signed 32-bit integer from the socket 4
                              readObject(  ):*

Reads an AMF-encoded object from the socket n
                              readShort(  ):int

Reads a signed 16-bit integer from the socket 2
                              readUnsignedByte(  ):uint

Reads an unsigned byte from the socket 1
                              readUnsignedInt(  ):uint

Reads an unsigned 32-bit integer from the socket 4
                              readUnsignedShort(  ):uint

Reads an unsigned 16-bit integer from the socket 2
                              readUTF(  ):String

Reads a UTF-8 string from the socket n

There are also two additional read methods not covered in Table 24-1. They are readBytes( ) and readUTFBytes( ). The readBytes( ) method is the only Socket read method to not return a value, and it takes the following three parameters:



bytes

A flash.util.ByteArray instance to read the data from the socket into.



offset

A uint value specifying the offset into bytes where read data from the socket should start being placed. The default value is 0.



length

A uint value for the number of bytes to read. The default is 0, meaning all available data will be read from the socket into the bytes ByteArray.

The readUTFBytes( ) method, on the other handle, takes a single length parameter specifying the number of UTF-8 bytes to read, and it returns the String corresponding to the read bytes.

Before reading data from a Socket, it is important to check the socket's bytesAvailable property first. Attempting to read more data than what is available will result in a flash.errors.EOFError.


The following code example connects to a socket server, and reads and displays the data sent from the server one byte at a time:

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( event:ProgressEvent ):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 );
      }
    }
  }
}

In the preceding example, if the socket server sends back a message (such as "Hello"), the output of the code would look like this when a client connects:

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

Once data is read from the Socket, it cannot be read again. For example, after reading a byte, that byte cannot be "put back" and read as part of an int later.


When the data received by a Socket object is ASCII text, you can reconstruct a string by using the readUTFBytes( ) method. The readUTFBytes( ) method requires that you tell it how many bytes to read and convert to a string. You can use bytesAvailable to read all the bytes:

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

The XMLSocket class behaves in a similar manner to the Socket class in regard to how it receives data from the server. In both cases, an event listener must be used to be notified that data is available due to Flash's asynchronous socket implementation. However, the process used to actually read the data is very different.

An XMLSocket instance dispatches a data event when data has finished downloading from the server. The data event, defined by the flash.events.DataEvent.DATA constant, contains a String data property that contains the information received from the server.

When using XMLSocket, the data returned from the server is always interpreted as a String. There are no specific read methods for various datatypes.


The data returned from the server is the raw server response. Because of this, you're not limited to just using XML with XMLSocket connections, but rather you can send and receive plain String information as well. If you're expecting XML back from the server, however, you must first convert the data into an XML instance before working with it.

The following code example initiates a connection over XMLSocket to a server running on port 2900 on the local computer. After the connection is successfully made, a <test> message is sent to the server. The onData event listener handles the response from the server, which in this case is the string <response><test success='true'/></response>. You can see that the data property of the event passed to onData is just a String, and that the XML constructor is used to convert the String into an XML instance. Finally, E4X syntax is used to output a portion of the converted XML (for more information about working with XML and using E4X, see Chapter 21):

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( event:DataEvent ):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( response.test.@success );
    }
  }
}

Before the data event can be dispatched, the XMLSocket instance must detect the null byte ('\\0') from the server. That is, sending a string from the server is not enough for the client to receive it. Instead, the string must be terminated by the null byte.


See Also

Recipes 18.2, 24.1, and 24.4


Previous Page
Next Page
Converted from CHM to HTML with chm2web Pro 2.85 (unicode)