Listen for incoming connections in AS3 (AIR) Client whithout using Server Socket

Schrödinger's Box picture Schrödinger's Box · Dec 19, 2012 · Viewed 7.5k times · Source

I managed to create a C# Server that sends files to AS3(AIR) Clients using sockets. On the AS3 side I'm using the flash.net.Socket library to receive the data through TCP.

This is how it works:
-> I turn on my server, and it listens for clients (plus I can create a list of connected devices);
-> I turn on my client and it automatically receives the data;

The trigger event to receive the data is made on the client, i.e., I simply turn the server ON and when the client turns ON, it gets the data, triggering these events:

socket.addEventListener(Event.CONNECT, onConnect); -> to connect to the server  
socket.addEventListener(Event.SOCKET_DATA, onDataArrival); -> to receive the data  

Now I want to do something different. I don't want to trigger it on the client, I want the server to do that, i.e, I want to turn on my client and on the server put in what client will get the data.

So why am I trying to make the client a client/server? Well, because my server is one machine, and my clients are XXX mobile devices that connect the server, and this is my approach to accomplish this.

So, given what I just said, I managed to create my AS3 client/server app that works just like I want it, using the flash.net.ServerSocket library.

First I put the client listening:

serverSocket.bind(portNumber, "10.1.1.212");
serverSocket.addEventListener(ServerSocketConnectEvent.CONNECT, onConnectServer);
serverSocket.listen();

And then I receive the data using the flash.net.Socket Event.SOCKET_DATA

And that's pretty much it. Works just like I want it to.
However, the flash.net.ServerSocket is not compatible with mobile devices, yet...

So here's my problem: I need to send files from C# server (that needs to listen for clients so I can create a list of connected devices) to AS3(AIR) Clients, but I have to define which client is getting the data on the server, and the clients need to be prepared to receive that data anytime, therefore, listening, but there's a lot of them, that's why I consider them as clients.

And my question is: Is there a way to make a client listen for incoming connections and triggering an event when it happens, whithout using the Server Socket in AS3?

Also, if you have a different approach to accomplish my goal whithout using the C# server <-> AS3 client/server logic, please feel free to kick in your opinion.

Answer

david.emilsson picture david.emilsson · Dec 19, 2012

Yes. Your client should connect to the server via a flash.net.Socket (doc) or flash.net.XMLSocket (doc). In most cases, you only need one server to which many clients can connect. It's not entirely clear why you have servers at both ends?

Edit:

Below is a quick example of a client continuously listening for messages from the server using a Socket. This connects to the server and then waits (indefinitely) for data. When a chunk of data is received (in this case I'm expecting strings terminated by a new line character), the data is passed along with an event.

If you've tried this approach without success, you should look to see if there's any errors or if the connection is getting closed.

Document class:

package  {
    import flash.display.Sprite;

    public class Main extends Sprite {
        protected var socket:SocketTest;

        public function Main() {
            this.socket = new SocketTest();
            this.socket.addEventListener(SocketMessageEvent.MESSAGE_RECEIVED, onSocketMessage);
            this.socket.connect("127.0.0.1", 7001);
        }

        protected function onSocketMessage(e:SocketMessageEvent):void {
            var date:Date = new Date();
            trace(date.hoursUTC + ":" + date.minutesUTC + ":" + date.secondsUTC + " Incoming message: " + e.message);
        }
    }
}

SocketTest class:

package  {
    import flash.net.Socket;
    import flash.events.Event;
    import flash.events.IOErrorEvent;
    import flash.events.SecurityErrorEvent;
    import flash.events.ProgressEvent;
    import flash.errors.IOError;

    public class SocketTest extends Socket {
        protected var _message:String;

        public function SocketTest() {
            super();
            this._message = "";

            this.addEventListener(Event.CONNECT, socketConnected);
            this.addEventListener(Event.CLOSE, socketClosed);
            this.addEventListener(ProgressEvent.SOCKET_DATA, socketData);
            this.addEventListener(IOErrorEvent.IO_ERROR, socketError);
            this.addEventListener(SecurityErrorEvent.SECURITY_ERROR, socketError);
        }

        protected function socketData(event:ProgressEvent):void {
            var str:String = readUTFBytes(bytesAvailable);

            //For this example, look for \n as a message terminator
            var messageParts:Array = str.split("\n");

            //There could be multiple messages or a partial message, 
            //pass on complete messages and buffer any partial
            for (var i = 0; i < messageParts.length; i++) {
                this._message += messageParts[i];
                if (i < messageParts.length - 1) {
                    this.notifyMessage(this._message);
                    this._message = "";
                }
            }
        }

        protected function notifyMessage(value:String):void {
            this.dispatchEvent(new SocketMessageEvent(SocketMessageEvent.MESSAGE_RECEIVED, value));
        }

        protected function socketConnected(event:Event):void {
            trace("Socket connected");
        }

        protected function socketClosed(event:Event):void {
            trace("Connection was closed");
            //TODO: Reconnect if needed
        }

        protected function socketError(event:Event):void {
            trace("An error occurred:", event);
        }
    }
}

SocketMessageEvent class:

package  {
    import flash.events.Event;

    public class SocketMessageEvent extends Event {
        public static const MESSAGE_RECEIVED:String = "messageReceived";

        protected var _message:String;

        public function SocketMessageEvent(type:String, message:String = "", bubbles:Boolean = false, cancelable:Boolean = false) {
            super(type, bubbles, cancelable);
            this._message = message;
        }

        public function get message():String {
            return this._message;
        }
    }
}

As a test I set the server up to send a message every 5 seconds, this is the output in the console:

Socket connected
21:36:24 Incoming message: Message from server: 0
21:36:29 Incoming message: Message from server: 1
21:36:34 Incoming message: Message from server: 2
21:36:39 Incoming message: Message from server: 3
21:36:44 Incoming message: Message from server: 4
21:36:49 Incoming message: Message from server: 5