javaactionscript-3flashsocketsxmlsocket

Java Socket Server


I am already loosing it...

I've built a simple Flash application via FlashDevelop (AS3) and I want it to communicate to a Server. I created then a simple Socket Java Application with the code:

Main.java:

import org.xsocket.connection.*;

public class Main
{
    protected static IServer srv = null;

    public static void main(String[] args) 
    {
        try
        {
            srv = new Server(8090, new xSocketDataHandler()); 
            srv.run();
        }
        catch(Exception ex)
        {
            System.out.println(ex.getMessage());
        }
    }

    protected static void shutdownServer()
    {
        try
        {
            srv.close();
        }
        catch(Exception ex)
        {
            System.out.println(ex.getMessage());
        }        
    }
}

and xSocketDataHandler.java:

import java.io.IOException;
import java.nio.BufferUnderflowException;
import java.nio.channels.ClosedChannelException;
import java.util.*;
import org.xsocket.*;
import org.xsocket.connection.*;


public class xSocketDataHandler implements IDataHandler, IConnectHandler, IDisconnectHandler
{
    private Set<INonBlockingConnection> sessions = Collections.synchronizedSet(new HashSet<INonBlockingConnection>());

    public boolean onData(INonBlockingConnection nbc) throws IOException, BufferUnderflowException, ClosedChannelException, MaxReadSizeExceededException 
    {
        try
        {
            String data = nbc.readStringByDelimiter("\0");

            if(data.trim().length() > 0)
            {   
                System.out.println("Incoming data: " + data);

                if(data.equalsIgnoreCase("<policy-file-request/>"))
                {
                    nbc.write("<cross-domain-policy>" +
                            "<allow-access-from domain=\"*\" secure=\"false\" />" +
                            "<allow-access-from domain=\"*\" to-ports=\"8090\"/>" +
                            "</cross-domain-policy>\0");
                    return true;
                }

                String[] message = data.split("~");

                sendMessageToAll(nbc, message[0], message[1]);

                if(message[1].equalsIgnoreCase("SHUTDOWN"))
                    Main.shutdownServer();                
            }
        }
        catch(Exception ex)
        {
            System.out.println("onData: " + ex.getMessage());
        }

        return true;
    }

    private void sendMessageToAll(INonBlockingConnection nbc, String user, String message)
    {
        try
        {
            synchronized(sessions)
            {
                Iterator<INonBlockingConnection> iter = sessions.iterator();

                while(iter.hasNext())
                {
                    INonBlockingConnection nbConn = (INonBlockingConnection) iter.next();

                    if(nbConn.isOpen())
                        nbConn.write("<b>" + user + "</b>: " + message + "<br />\0");
                }
            }

            System.out.println("Outgoing data: " + user + ": " + message);
        }
        catch(Exception ex)
        {
            System.out.println("sendMessageToAll: " + ex.getMessage());
        }            
    }

    public boolean onConnect(INonBlockingConnection nbc) throws IOException, BufferUnderflowException, MaxReadSizeExceededException
    {
        try
        {
            synchronized(sessions)
            {
                sessions.add(nbc);            
            }

            System.out.println("onConnect");
        }
        catch(Exception ex)
        {
            System.out.println("onConnect: " + ex.getMessage());
        }

        return true;
    }

    public boolean onDisconnect(INonBlockingConnection nbc) throws IOException
    {
        try
        {
            synchronized(sessions)
            {
                sessions.remove(nbc);            
            }

            System.out.println("onDisconnect");
        }
        catch(Exception ex)
        {
            System.out.println("onDisconnect: " + ex.getMessage());
        }        

        return true;
    }
}

So, the problem is:

I start the Java Application, and it runs perfectly. I start my Flash application and It runs, creates the socket object, connects to my server (all in my computer) the server gets the connection attempt but, at:

nbc.readStringByDelimiter("\0");

it says that nbc is closed, and the server catches the exception: "onData: channel is closed (read buffer size=0)"

Does anyone knows why always I get this? Doesn't matter how I write it, use Socket, XMLSocket, xSocketDataHandler, or anyhting, I keep getting the closed channel error.

What am I doing wrong??

Thanks.

EDIT1:

The AS3 Code:

This is my Socket class:

import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
import flash.events.SecurityErrorEvent;
import flash.net.Socket;
/**
* ...
* @author 9MS
*/
public class GameSocket extends Socket 
{
    private var host:String;
    private var port:int;

    public function GameSocket(host:String="187.127.89.158", port:int=8090)
    {
        super(host, port);

        socketConnect();
    }

    public function socketConnect():Boolean {


        addEventListener(Event.CONNECT, onConnect);
        addEventListener(ProgressEvent.SOCKET_DATA, onResponse);
        addEventListener(Event.CLOSE, onClose);
        addEventListener(IOErrorEvent.IO_ERROR, onError);
        addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecError);

        try {
            connect(this.host, this.port);
        }
        catch (e:Error) {
            trace("Error on connect: " + e);
            return false;
        }
        return true;
    }

    public function sendData(msg:String):void {
        msg += "\0";

        try {
            writeUTFBytes(msg);
            flush();
            trace("Message sent: " + msg);
        }
        catch(e:Error) {
            trace("Error sending data: " + e);
        }

    }

    private function onConnect(e:Event):void {
        trace("Connected: "+e);
    }

    private function onResponse(e:ProgressEvent):void {
        trace("Receiving Data: " + e);

        var resp:String = readUTFBytes(bytesAvailable);

    }

    private function onClose(e:Event):void {
        trace("Connection Closed: " + e);
        close();
    }

    private function onError(e:IOErrorEvent):void {
        trace("IO Error: " + e.text);
        close();
    }

    private function onSecError(e:SecurityErrorEvent):void {
        trace("Security Error: " + e.text);
        close();
    }

}

Solution

  • So, I've solved the problem. A very important thing in flash communication throught sockets, is that Flash opens the socket bridge, asks for the policy file, and than closes it after. So, in your server, you must receive the connection, checks for a policy-file-request, send the policy file and close the bridge. After receiving the policy file, Flash will open the connection again, and communicate normally without asking for a policy file again.

    So, after getting a new connection, you must start your logic normally but, if you receive a policy-file-request, just answer with the policy file and close the connection.