AboutServicesPartnersHostingContact  

HeliantTM Whitepaper:
XMLSocket Simplified

by Shengdar Tsai
xmlsocket@heliant.net

Introduction
This is a simple foray into the world of Flash5 XMLsocket. After searching the net for a simple XMLsocket server, and not really finding one that really fit my needs, I decided to write one in Perl. This document relates some experiences related to writing a client-server application using Perl sockets, and Flash 5 XMLsocket.

Raison d'être
What is this, and what is it good for? Documented in this whitepaper is a fully functional client/server application using Flash/XMLsocket and Perl. Please note, the server program written in perl is NOT a CGI script. This application is intentionally not feature rich -- the idea is that it exists as a simple framework off which you can build.

Interesting Discoveries
We'll jump straight to some interesting points I found while working with XMLsocket. First, XMLsocket does not necessarily need to communicate in an XML protocol as it's name suggests. The XMLsocket constructor in Flash simply creates a standard socket. Upon connection, you have access to the raw connection data. In order to use the XML functions in flash, the document you get must be in XML. However, if you want to communicate in your own protocol, you can manipulate the datastream you receive directly.

XMLSocket Protocol
Here are the relevant excerpts from Flash 5 documentation.

      When you use the XMLSocket object to create a socket connection with a server, you must use a port numbered 1024 or higher. (Ports with lower numbers are commonly used for Telnet, FTP, the World Wide Web, or Finger.)

      To use the XMLSocket object, the server computer must run a daemon that understands the protocol used by the XMLSocket object. The protocol is as follows:

      • XML messages are sent over a full-duplex TCP/IP stream socket connection.
      • Each XML message is a complete XML document, terminated by a zero byte.
      • An unlimited number of XML messages can be sent and received over a single XMLSocket connection.
Again, the second bullet point from the documentation is not entirely true. However, whether or not the message is in XML format, it must be terminated by a zero byte. A zero byte is the ASCII null byte, often "\0". Why would you not use XML format? It's entirely a matter of programmer choice and discretion. XML format is more human readable, however it adds significant protocol overhead, often around 30%.

Flash Client Code
Some explanatory commentary. Most of the code should (hopefully) be fairly clear. In the last function, newXML, the input string is converted to a string. You can use the raw data in whatever manner you choose.

        // Functions

        function connect() {
            // Create new XMLSocket object
            socket = new XMLSocket();

            // Hardcoded connection sequence for now
            socket.connect('raydea.com', 7777);

            // Override appropriate functions
            socket.onXML = newXML;
            socket.onConnect = newConnection;
            socket.onClose = endConnection;
        }

        function newConnection (success) {
            if (success) {
                serverStatus = "connected!";
            }
            else {
                serverStatus = "error connecting";
            }
        }

        function endConnection () {
            serverStatus = "disconnected";
        }

        function newXML (input) {
            // convert XML object to string
            var receivedText = input.toString();
        }

Perl Server Code

This perl server use IO::Select to manage the open connections. It is a simple "echo server" in that it broadcasts whatever is sent, to all connected clients.

The basic concept behind the perl server is to create a socket, and then use IO::Select (an object oriented interface to the select() function) to switch between the various active sockets. The IO::Select handler simply blocks when no activity is detected on any of the sockets.

There are two main foreach loops in this simple server. The first foreach loop processes each of the sockets that is "read-ready", i.e. that has new data inbound to the server. This data can be processed in whatever manner is necessary. In this server instance, null data is assumed to be a disconnection request.

The second foreach loop iterates through all the sockets that are "write-ready." It is in this stage that you can target messages to specific clients, among other things.

The sockets in both of the foreach loops are given by the variable $fh. A unique number is associated with each socket, and can be accessed with the following syntax -- fileno($fh).

        #!/usr/bin/perl

        # This is an XMLSocket multiuser server, for use with Flash 5
        # If you don't know what XMLSocket is, you shouldn't be using
        # this program.  

        use IO::Socket;
        use IO::Select;

        # Set the input terminator to a zero byte string, pursuant to the
        # protocol in the flash documentation.
        $/ = "\0";

        # Create a new socket, on port 7777
        $lsn = new IO::Socket::INET(Listen => 1, 
                                    LocalPort => 7777,
                                    Reuse => 1,
                                    Proto => 'tcp' )
           or die ("Couldn't start server: $!");

        # Create an IO::Select handler
        $sel = new IO::Select( $lsn );

        # Close filehandles

        close(STDIN); close(STDOUT);

        warn "Server ready.  Waiting for connections . . . \n";

        # Enter into while loop, listening to the handles that are available.
        while( @read_ready = $sel->can_read ) {

            foreach $fh (@read_ready ) {

                # Create a new socket
                if($fh == $lsn) {
                    $new = $lsn->accept;
                    $sel->add($new);
                    push( @data, fileno($new) . " has joined.");
                    warn "Connection from " . $new->peerhost . ".\n";
                }

                # Handle connection
                else {

                    $input = <$fh>;
                    
                    chomp $input;

                    if ( $input eq '') {
                        push( @data, fileno($fh) . " has left.");
                        warn "Disconnection from " . $new->peerhost . ".\n";				
                        $sel->remove($fh);
                        $fh->close;
                    }
                    else {
                        $output = fileno($fh) . ": $input";
                        push( @data, $output );

                    }
                }

            }

            # Write to the clients that are available
            foreach $fh ( @write_ready = $sel->can_write(0) ) {
                foreach $line (@data) {
                    print $fh "$line\0";
                }
            }
                
            undef @data;

        }

        warn "Server ended.\n";

Flash Bugs And Workarounds
I've spent a fair amount of time trying to figure out the problems with Flash 5 and text scrolling. Here is a brief summary of the trials and tribulations.

  • Flash player r30, the version that comes with Flash has a major scrolling bug. It doesn't update maxscroll properly, or allow you to set text.scroll when the text has changed.
  • The current version of the flash player updates text.maxscroll one frame after the text has actually changed.
  • The solution was found in Colin Moock's chat server, which suggests in a comment to use onClipEvent ( enterFrame ). Create a scroll manager by having an invisible movieclip with an enterFrame event handler. This will allow you to update a boolean flag when the text has changed, and have the movieclip check and then scroll the textfield appropriately. Here's an example:
            onClipEvent ( enterFrame ) {
                if ( _root.documentUpdated ) {
                    this.text.scroll = this.text.maxscroll - 1;
                    _root.documentUpdated = false;
                }
            }
    

Source Code
The source for both the client and server are freely available here released by Heliant, Inc.:
http://heliant.net/~stsai/code/xmlsocket.tar.gz

This source is governed by the terms of the BSD License or the GPL.

Comments, Questions, Patches, Flames
I'd love to hear any comments that you may have on the code, the whitepaper, etc. If you've done something cool with this server, I would also be happy to put a link in the examples section.

I can be reached at xmlsocket@heliant.net.


© 2001 This document, and all code copyright Shengdar Tsai. All rights reserved.