Flash to Java socket lost packets when on 3G

187 views Asked by At

I'm trying to communicate flash android app to java using sockets, but when the app is connected via 3G - many packages get lost (not received).

Here is my Java server:

public class SServer implements Runnable  {

protected int          serverPort   = 9070;
protected ServerSocket serverSocket = null;
protected boolean      isStopped    = false;
protected List<ClientRunnable> clients = new ArrayList<ClientRunnable>();
protected int msgCounter = 0;

public static void main(String args[]) {
    SServer server = new SServer();
    new Thread(server).start();
}

public void run(){

    //init spam timer
    new Timer().schedule(new TimerTask() {              
        @Override
        public void run() {
            for (ClientRunnable cr : clients) {
                cr.send("Message " + msgCounter++);
                cr.send("Message " + msgCounter++);
                cr.send("Message " + msgCounter++);
            }       
        }
    }, 0, 2000);

    openServerSocket();
    while(! isStopped()){
        Socket clientSocket = null;
        try {
            clientSocket = this.serverSocket.accept();
        } catch (IOException e) {
            if(isStopped()) {
                System.out.println("Server Stopped."); return;
            }
            throw new RuntimeException("Error accepting client connection", e);
        }
        ClientRunnable cr = new ClientRunnable(clientSocket);
        clients.add(cr);
        new Thread(cr).start();
    }
    System.out.println("Server Stopped.") ;
}

private synchronized boolean isStopped() {
    return this.isStopped;
}


private void openServerSocket() {
    try {
        this.serverSocket = new ServerSocket(this.serverPort);
        System.out.println("Server Started.") ;
    } catch (IOException e) {
        throw new RuntimeException("Cannot open port 8080", e);
    }
}

}

And this is the client thread:

public class ClientRunnable implements Runnable{

protected Socket clientSocket = null;
protected Boolean connected = false;
protected BufferedReader in = null;
protected PrintStream os = null;


public ClientRunnable(Socket clientSocket) {
    this.clientSocket = clientSocket;
}

public void run() {

    connected = true;

    try {
        //InputStream input  = clientSocket.getInputStream();
        in = new BufferedReader (new InputStreamReader(clientSocket.getInputStream(), "UTF-8" ));
        os = new PrintStream(clientSocket.getOutputStream());

        //read
        //..


    } catch (IOException e) {
        onError(e);
        connected = false;
        closeConnection();
    } 
}

private void closeConnection() {
    os.close();
    //other closing code..
}

public void send(String data) {
    try {
        byte[] dataBytes = data.getBytes("UTF-8");
        //will contain all bytes plus zery byte flash delimiter
        byte[] allBytes = new byte[dataBytes.length + 1];
        System.arraycopy(dataBytes, 0, allBytes, 0, dataBytes.length);
        allBytes[allBytes.length-1] = (byte)0;
        synchronized (this) {
            Thread.sleep(50); //non 3G workaround
            os.write(allBytes);
            os.flush();
        }
    } catch (Exception e) {
        e.printStackTrace();
         onError(e);
    } 
}

public void onError(Exception ex) {
    ex.printStackTrace();
}

}

Please note that Thread.sleep(50); before every send write - fixes the problem on non regular non 3G connections. But when the app is runnung on 3G, this value must be much higher and there are still missed pachages sometimes.

Here is my flex client:

<?xml version="1.0" encoding="utf-8"?>

<fx:Script>
    <![CDATA[
        import spark.events.ViewNavigatorEvent;

        private var _socket:Socket;
        private var _host:String = "<MY HOST IP>";
        private var _port:int = 9070;

        protected function onViewActivate(event:ViewNavigatorEvent):void {
            _socket = new Socket(_host, _port);
            _socket.addEventListener(Event.CLOSE, function(e:Event):void{ ta.appendText("Close\n"); });
            _socket.addEventListener(Event.CONNECT, function(e:Event):void{ ta.appendText("Connect\n"); });
            _socket.addEventListener(IOErrorEvent.IO_ERROR, function(e:IOErrorEvent):void{ ta.appendText("IO Error\n"); });
            _socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function(e:IOErrorEvent):void{ ta.appendText("Security Error\n"); });
            _socket.addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler);
        }

        private function socketDataHandler(event:ProgressEvent):void {
            var socket:Socket = event.target as Socket;
            var str:String = socket.readUTFBytes(socket.bytesAvailable);
            ta.appendText(str+"\n");
        }

    ]]>
</fx:Script>

<s:VGroup width="100%" height="100%">
    <s:TextArea id="ta" skinClass="spark.skins.mobile.TextAreaSkin" width="100%" height="100%" />
    <s:Button label="Reconnect" click="_socket.connect(_host, _port)" />
</s:VGroup>

And this is how it finally looks like: (note that the sequenced sendings are problematic, although there is 50ms delay)

enter image description here

As you can see many of the sequencial messages are not received. Increasing the delay helps, but not always (and is bad as solution).

The Flex project is uploaded HERE

The Java project is uploaded HERE

1

There are 1 answers

0
Howard Roark On BEST ANSWER

I recently had a similar problem on a socket connection running between AS and Java. I solved it by making a message queue in Java, adding a message ID to my messages and then making the ActionScript side respond with the messageID before the next message in queue is sent. That guaranteed that the same message went out over and over until AS responded that it got it.