Even in ActionScript, building client-side socket software is not terribly difficult. Remember that ActionScript has two different objects, XML and XMLSocket. These are entirely distinct. An XML object is a data package. It has many properties and many methods , but they all deal with a tree of data that is organized along the principles of XML and that can translate itself from string representation to data object and back with great reliability.
An XMLSocket is not a data interface at all; it is a communications interface. The operative word is "socket," and its methods are similar to the socket function in PHP, Perl or Unix.
Even when compared to a fairly dumb PHP socket function like fsockopen() that provides limited client-only control, the ActionScript methods seem quite simplified.
connect( host, port)
This method begins the process of connecting to a remote socket. The default host is the one from which the swf file was served . In the case of browser-based swf files, the host must be in the same subdomain as the source of the swf, so this default is nearly a requirement. (The default is requested by a null host parameter, such as ""or the keyword null .) In fact, experimentation reveals an even simpler fact: You must use null . Correct identification of the server (either by full name, domain name , or by numeric IP address) is not recognized properly by Flash. If you request a connect to your own server by naming it, Flash refuses the connection. If you use the null parameter it succeeds.
This is quite disappointing. The domain perimeter security feature is generally an impediment to the developer. But here it could be a great boon. If a domain name is hardcoded in a Flash connection, the application will communicate properly only when it is hosted in that domain. This would make the .swf file inoperable if it were swiped by a pirate webmaster. The domain perimeter principle can protect a publisher's intellectual property, but current implementations fall short. The identification of the host is relative, not absolute.
The port address must be known by Flash, either by some global convention or by an arbitrary installation-dependent choice (is typically the latter). Hardcoding this port assignment into Flash code may seem reasonably expedient, and often it is. However, a conscientious programmer might allow his client to ask the service for a port number before launching the socket. This would complicate the process and require two separate mechanisms. First, an HTTP connection, presumably using XML.sendAndLoad() , enables the Flash client to request a port number from the server. The second phase of communication starts with XMLSocket.connect() directed to that port.
Keep in mind that socket connection is an asynchronous process. It is not unusual for the connection to take a few seconds to establish. In many active Flash displays, a pause of a few seconds is as subtle as a car crash.
So this function only initiates the connection process. It returns immediately with true or false , but these values cannot be relied on for much. In fact, the return value tells us only whether ActionScript even bothered to attempt a connection. A false means that our parameters failed ActionScript's two basic gate-keeping rules: either our port number was below 1024 or our host parameter (in the case of web-based Flash) was non-null. A true result does not mean that the domain exists or that the port number is legitimate .
This event handler allows us to complete the asynchronous connection. We can install a callback function to manage the outcome of the XMLSocket connection. The function we install is called by Flash when the connection is established or when the software times out unsuccessfully. (Flash does not allow us to tweak the number of retries or otherwise control this timeout.)
The function that is installed here should have a single boolean parameter: success. If success is true, it is time to fire up the socket activity we have planned. If unsuccessful , there needs to be (at a minimum) decent error reporting and perhaps even some sort of error recovery.
This is the method by which an XMLSocket closes itself. The object itself is not destroyed , and it can be used to connect again. Use delete() to remove the XMLSocket object.
There would seem to be symmetry between the connect/onConnect and the close/onClose methods that initiate and end a socket connection, but there isn't. True, connect() starts an asynchronous process that ends with onConnect . On the other hand, close() starts an immediate process. It does not cause onClose() to occur. Rather onClose() is invoked only when the XMLSocket is closed involuntarily. An outside process, most likely the server itself but possibly a communication break, causes the socket to close.
If we have installed an event handler, it is invoked by such breaks in the socket connection and gracefully manages the situation.
This is a method of the XMLSocket by which it sends an XML object across the connection. Note that the XMLSocket is not sending itself across the connection. As we considered earlier, this object embodies the connection, not the data that goes across. The XMLSocket is a socket; it is not XML. In design, it is a socket through which XML objects can transparently pass. This send() method will serialize the object, that is, convert it to a stream of text, using the XML object's toString() method.
In fact, the interface permits sending other data, as well. Strings are sent as is, and other data is serialized as well as possible. But this fact tempts us to create quick shortcuts that never seem to be updated. So we will forget this aspect of send() and concentrate on building honest systems for two-way transparent XML communication.
Note that send() , like connect() , is asynchronous. The call simply initiates the action. The actual performance occurs later. Unlike connect() , there is no callback function that tells us the results of the send() action. We send() our data ”and hope it gets there. In fact, it is only by observing the behavior of the application that we can tell if we succeeded or not.
This function handles the XML data received event of the socket. Unless we write and install a callback function, nothing will happen when data arrives across the socket. Rarely is this the desired behavior.
It is important to remember that the XML data received event does not happen when data is received. It occurs when an XML object is received. Specifically, it requires a complete, closed XML document terminated by a null byte.
Since packet transmission is fairly independent of the application code, it is not unusual for a data message to span several TCP packets or for one packet to hold several data messages. In the former case, the XML object is stitched together; in the latter case, the objects are individually broken out.
The parser is given each null terminated string to parse, and then it calls the onXML function we have installed. The system creates a legitimate XML object and passes it to the application as the parameter of the onXML function. It is the job of onXML to pick apart the nodes and do something interesting with the new object.
In our examples we need to be attentive. PHP does not automatically punch out XML documents; the opening and closing of tags is entirely our responsibility. (Opening and closing tags is not terribly hard, but often it is a challenge to nest the elements and wrap the response in a single element, a requirement of legitimate XML documents.)
Our attention is especially required because PHP does not naturally traffic in null-terminated strings. Note that in our code we explicitly append \0 to the end of each string we create in PHP. Coming from the other direction seems simpler, but it is also error prone: ActionScript sends null-terminated strings to the server. If we ignore the nulls, they do not disturb the PHP strings ”they are invisible. But in a chat system, for example, strings are churned around and passed back and forth from clients to server. If the nulls are not stripped out, they soon get mixed into the strings. Though benign in PHP, they break up the strings in ActionScript and spark recombinant chaos that is rarely fun or productive.
The XMLSocket concept is fresh and attractive. It sparks the imagination to create independent entities driven by little engines of connectivity to some outside work process. Even the most obvious opportunities are lively and exciting: a chat system, a live stockmarket ticker, and so on.
In many cases, XMLSockets can be a promising design choice, but be cautious. XMLSockets are not easy to establish and maintain. And it is tempting to create specialized XMLSocket objects for many components of an application. Each socket can exhibit different behavior when data is received; the sockets might share behaviors, as well, both standard and prototyped. While this is a clean, sturdy, object-oriented architecture in which each object maintains an independent link to the outside world, it is a little too academic for the real world.
Though sockets are simply abstractions, they do exact a finite cost. Each socket that is supported chews a bit of resources out of allocation on the remote server. Such an expense could quickly get out of hand in a design when many game characters , for example, are each driven by an individual socket connection.