ProblemYou want to read data from a socket server. SolutionFor 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. DiscussionReceiving 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.
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:
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.
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
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.
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 ); } } }
See AlsoRecipes 18.2, 24.1, and 24.4 |