Flutter sending UTF8 toJava/Kotlin's using DataInputStream and readUTF - java

Currently, we are trying to write a Flutter-Dart client (ported from a Java Client) using sockets for transferring plaintext-data and files.
The Server is written in Kotlin and works well with Kotlin clients sending a UTF Package (information about the binary package sent after), followed by a long package defining the package size and finally the binary data.
A small truncated sample code for the server is:
class DataProcessRunnable internal constructor(private val socket: Socket, private val onFileReceivedListener: OnFileReceivedListener) : Runnable {
private val dateFormat = SimpleDateFormat("HH-mm-ss")
private val dateDayFormat = SimpleDateFormat("yyyy-MM-dd")
override fun run() {
try {
DataInputStream(socket.getInputStream()).use { stream ->
print ("connected ${stream.toString()}")
val rawData = stream.readUTF();
print("Rawdata: $rawData")
val fileData = gson.fromJson(rawData, FileData::class.java)
fileData.ipAddress = socket.inetAddress.hostAddress
val fileSize = stream.readLong()
println("sender: " + socket.inetAddress)
println("Filedata:$fileData")
println("filesize:$fileSize")
var fileName = "noname"
val fileTransfer = FileTransfer()
fileTransfer.fileSize = fileSize
fileTransfer.filename = fileName
println("filename:$fileName")
try {
try {
try {
GZIPInputStream(stream).use { input ->
FileOutputStream(fileName).use { out ->
input.copyTo(out)
}
}
} catch (ex: Exception) {
ex.printStackTrace()
} finally {
println("Wrote File in GZIP")
}
fileTransfer.transferedSize = fileTransfer.fileSize
val fData = FileData()
fData.file = File(fileName)
fData.extras = fileData.extras
fData.ipAddress = socket.inetAddress.toString()
fData.type = fileData.type
onFileReceivedListener.fileReceived(fData)
} catch (ex: Exception) {
ex.printStackTrace()
}
} catch (ex: Exception) {
ex.printStackTrace()
}
}
} catch (ex: Exception) {
ex.printStackTrace()
}
}
}
When we use Flutter-Dart to establish a socket, we are trying to send the first UTF8-Package using that codesample. The connection is established but readUTF can't read any data.
await Socket.connect('dev1.local-cloud-server.local', 2555).then((socket) {
socket.writeln(gzip.encode(utf8.encode(fData.toString())));
socket.flush();
});
});
After trying around several methods to send a utf8 encoded string from flutter dart to java, the only way I was able to read the first package was using (on the serverside, code truncated):
private fun validateSocketConnection2(socket: Socket) {
Thread {
DataInputStream(socket.getInputStream()).use { stream ->
val rawData = stream.bufferedReader().forEachLine { println(it) }
print("Rawdata: $rawData")
}.start()
}
Using a bufferedreader i was able to read the utf8 encoded string properly, but that would break the whole kotlin server code for other clients. In Flutter-Dart we tried to use sockets.add(), sockets.write("...\n"), sockets.writeln(), await socket.flush() after every package sent and also socket.close() to ensure that all data were transmitted.
But we were not able to read data using readUTF as we do for any other Java/Kotlin/C# client.
What are we missing to get readUTF working?

Related

FileWriter closes websocket connection?

I am new to server programming and websockets and I've learnt a little bit of Java 8 this year. In school we had a project where a client webpage opens your webcam, takes a photo of a barcode and then shows a photo and the nutritional value of said product. You can also just send a raw barcode number and that is what is done in this example
My side of the project was to implement a java websocket server (the backend) using the glassfish tyrus library, then receiving the number of the barcode in string format and making a request to openfoodfacts.org using their api. Finally I parsed the json file and sent it back as string format so the client app can read the string and show the correct information (product name, image url, etc)
My code is organized into two files, Serveur.java establishes a websocket server for the client to connect to and ProduitApi.java gets the information from openfoodfacts.org with the given barcode from the client.
public class Serveur {
#javax.websocket.server.ServerEndpoint(value = "/websocket")
public static class EndPoint {
#javax.websocket.OnClose
public void onClose(javax.websocket.Session session, javax.websocket.CloseReason close_reason) {
System.out.println("onClose: " + close_reason.getReasonPhrase());
}
#javax.websocket.OnError
public void onError(javax.websocket.Session session, Throwable throwable) {
System.out.println("onError: " + throwable.getMessage());
}
#javax.websocket.OnMessage
public void onMessage(javax.websocket.Session session, String message) {
System.out.println("Message from client: " + message);
//Creation du produit avec le message du client
try {
ProduitApi produit = new ProduitApi(message);
session.getBasicRemote().sendText(produit.print());
} catch (Exception e) {
e.printStackTrace();
}
}
#javax.websocket.OnOpen
public void onOpen(javax.websocket.Session session, javax.websocket.EndpointConfig ec) throws java.io.IOException {
System.out.println("OnOpen... " + ec.getUserProperties().get("Author"));
session.getBasicRemote().sendText("{\"Handshaking\": \"Yes\"}");
}
}
public static void main(String[] args) {
Server server;
server = new Server ("localhost", 8025, "/BetterFood", null, EndPoint.class);
try {
server.start();
System.out.println("--- server is running");
System.out.println(java.nio.file.FileSystems.getDefault().getPath("client") );
System.out.print("Please press a key to stop the server.");
java.io.BufferedReader reader = new java.io.BufferedReader(new java.io.InputStreamReader(System.in));
reader.readLine();
} catch (Exception e) {
e.printStackTrace();
} finally {
server.stop();
}
}
}
as you can see, when I receive the 'barcode' message, onMessage() gets called. There I instantiate an object of class ProduitApi to use the barcode to then return the information
This is my ProduitApi file without some unnecessary details
package com.gabi.serveur;
/**
*
* #author gabriel
*/
[imports]
public class ProduitApi {
private java.lang.String barcode;
final private java.net.URL url;
private java.net.URLConnection connection;
JsonObjectBuilder constructeur_objet = Json.createObjectBuilder();
String string_json;
ProduitApi(java.lang.String barcode)throws MalformedURLException, IOException {
this.barcode = barcode;
this.url = new java.net.URL("http://world.openfoodfacts.org/api/v0/product/" + this.barcode + ".json");
connection = url.openConnection();
stream();
}
public void stream() throws IOException{
if (connection != null) {
java.io.InputStreamReader response = new java.io.InputStreamReader(connection.getInputStream());
javax.json.stream.JsonParser parser=javax.json.Json.createParser(response);
while (parser.hasNext()) {
[parsing inputStream into JsonObject]
}
public String print()throws IOException{
string_json = constructeur_objet.build().toString();
System.out.print(string_json);
//FileWriter file = new FileWriter("serveur/src/main/java/com/gabi/serveur/json/final.json");
//file.write(string_json);
//file.close();
return string_json;
}
}
My problem comes from the last function ProduitApi.print() , it is supposed to return the parsed json in string form so I can send it via the sendText() as well as printing the result into my console so I can see if everything went right. As you can see there are somme commented lines; The FileWriter object that I had created was used with the purpose of writing said string to a file in my pc and let me check inside.
HOWEVER
and here is what I don't understand, If I uncomment those lines so that the print function can also write the file to my drive, The Connection Closes and then Opens again
It can be seen in the console where after printing the json string, it prints OnClose, followed by OnOpen Signaling the connection was reset for some reason.
If I remove the FileWriter section, the connection works normally, the client's connection stays open and he can make another request
End of Console Message after request:
...cuits x22 biscuits fourrés - 304g","qte":"304 g","img":"https://images.openfoodfacts.org/images/products/800/050/031/0427/front_fr.177.400.jpg"}onClose: OnOpen... null...
Finally, my question is just why writing to a file makes my program behave this way (resetting the connection). Does it have anything to do with how streams work?
I accidentally commented the filewriter portion when another Ide said it didn't find the file because I had opened the project from a different directory.

Reflection and Invoking Method from Java to Kotlin

I'm trying to convert the following reflection into Kotlin. The following uses reflection to call an RFCOMMs function so it can take a port/channel as an input instead of UUID. I have all my program in Kotlin. Anyone know how to write this in Kotlin?
int bt_port_to_connect = 5;
BluetoothDevice device = mDevice;
BluetoothSocket deviceSocket = null;
...
// IMPORTANT: we create a reference to the 'createInsecureRfcommSocket' method
// and not(!) to the 'createInsecureRfcommSocketToServiceRecord' (which is what the
// android SDK documentation publishes
Method m = device.getClass().getMethod("createInsecureRfcommSocket", new Class[] {int.class});
deviceSocket = (BluetoothSocket) m.invoke(device,bt_port_to_connect);
Updating with recommendation:
class BluetoothClient(device: BluetoothDevice): Thread() {
// https://stackoverflow.com/questions/9703779/connecting-to-a-specific-bluetooth-port-on-a-bluetooth-device-using-android
// Need to reflection - create RFCOMM socket to a port number instead of UUID
// Invoke btdevice as 1st parameter and then the port number
var bt_port_to_connect = 5
var deviceSocket: BluetoothSocket? = null
private val socket = device.createInsecureRfcommSocketToServiceRecord(uuid)
val m = device::class.declaredFunctions.single { it.name == "createInsecureRfcommSocket" }
m.call(device, bt_port_to_connect)
override fun run() {
try {
Log.i("client", "Connecting")
this.socket.connect()
Log.i("client", "Sending")
val outputStream = this.socket.outputStream
val inputStream = this.socket.inputStream
try {
outputStream.write(message.toByteArray())
outputStream.flush()
Log.i("client", "Sent")
} catch(e: Exception) {
Log.e("client", "Cannot send", e)
} finally {
outputStream.close()
inputStream.close()
this.socket.close()
}
}
catch (e: IOException) {
println("Socket Failed")
}
}
}
You can really use exactly the same code, just convert it to Kotlin:
val m = device::class.java.getMethod("createInsecureRfcommSocket", Int::class.java)
m.invoke(device, bt_port_to_connect)
Or you can use Kotlin reflection:
val m = device::class.declaredFunctions.single { it.name == "createInsecureRfcommSocket" }
m.call(device, bt_port_to_connect)
I don't know if there is any better way to find a function with provided name. You can create an extension function to make it cleaner. You may also need to check parameters if this function has overrides.

Uploading file as stream in play framework 2.0

I'm writing a play 2.0 java application that allows users to upload files. Those files are stored on a third-party service I access using a Java library, the method I use in this API has the following signature:
void store(InputStream stream, String path, String contentType)
I've managed to make uploads working using the following simple controller:
public static Result uploadFile(String path) {
MultipartFormData body = request().body().asMultipartFormData();
FilePart filePart = body.getFile("files[]");
InputStream is = new FileInputStream(filePart.getFile())
myApi.store(is,path,filePart.getContentType());
return ok();
}
My concern is that this solution is not efficient because by default the play framework stores all the data uploaded by the client in a temporary file on the server then calls my uploadFile() method in the controller.
In a traditional servlet application I would have written a servlet behaving this way:
myApi.store(request.getInputStream(), ...)
I have been searching everywhere and didn't find any solution. The closest example I found is Why makes calling error or done in a BodyParser's Iteratee the request hang in Play Framework 2.0? but I didn't found how to modify it to fit my needs.
Is there a way in play2 to achieve this behavior, i.e. having the data uploaded by the client to go "through" the web-application directly to another system ?
Thanks.
I've been able to stream data to my third-party API using the following Scala controller code:
def uploadFile() =
Action( parse.multipartFormData(myPartHandler) )
{
request => Ok("Done")
}
def myPartHandler: BodyParsers.parse.Multipart.PartHandler[MultipartFormData.FilePart[Result]] = {
parse.Multipart.handleFilePart {
case parse.Multipart.FileInfo(partName, filename, contentType) =>
//Still dirty: the path of the file is in the partName...
String path = partName;
//Set up the PipedOutputStream here, give the input stream to a worker thread
val pos:PipedOutputStream = new PipedOutputStream();
val pis:PipedInputStream = new PipedInputStream(pos);
val worker:UploadFileWorker = new UploadFileWorker(path,pis);
worker.contentType = contentType.get;
worker.start();
//Read content to the POS
Iteratee.fold[Array[Byte], PipedOutputStream](pos) { (os, data) =>
os.write(data)
os
}.mapDone { os =>
os.close()
Ok("upload done")
}
}
}
The UploadFileWorker is a really simple Java class that contains the call to the thrid-party API.
public class UploadFileWorker extends Thread {
String path;
PipedInputStream pis;
public String contentType = "";
public UploadFileWorker(String path, PipedInputStream pis) {
super();
this.path = path;
this.pis = pis;
}
public void run() {
try {
myApi.store(pis, path, contentType);
pis.close();
} catch (Exception ex) {
ex.printStackTrace();
try {pis.close();} catch (Exception ex2) {}
}
}
}
It's not completely perfect because I would have preferred to recover the path as a parameter to the Action but I haven't been able to do so. I thus have added a piece of javascript that updates the name of the input field (and thus the partName) and it does the trick.

How to read response from remote server using Java Sockets

Part of a Java program I'm creating needs to talk to a service on a remote machine. That remote machine is running a service (written in Delphi I believe) on a Windows platform.
I need to connect to that machine, send command strings and receive (String) responses.
If I connect using Linux CLI telnet session I get responses as expected:
[dafoot#bigfoot ~]$ telnet [host IP] [host port]
Trying [host IP]...
Connected to [host IP].
Escape character is '^]'.
Welcome to MidWare server
ping
200 OK
ProcessDownload 4
200 OK
In the above the lines 'ping' and 'ProcessDownload 4' are me typing in the terminal, other lines are responses from remote system.
I created a Main in my Java class that will do the work to call the appropriate methods to try and test this (I've left out irrelevant stuff):
public class DownloadService {
Socket _socket = null; // socket representing connecton to remote machine
PrintWriter _send = null; // write to this to send data to remote server
BufferedReader _receive = null; // response from remote server will end up here
public DownloadServiceImpl() {
this.init();
}
public void init() {
int remoteSocketNumber = 1234;
try {
_socket = new Socket("1.2.3.4", remoteSocketNumber);
} catch (IOException e) {
e.printStackTrace();
}
if(_socket !=null) {
try {
_send = new PrintWriter(_socket.getOutputStream(), true);
_receive = new BufferedReader(new InputStreamReader(_socket.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
}
}
public boolean reprocessDownload(int downloadId) {
String response = null;
this.sendCommandToProcessingEngine("Logon", null);
this.sendCommandToProcessingEngine("ping", null);
this.sendCommandToProcessingEngine("ProcessDownload", Integer.toString(downloadId));
try {
_socket.close();
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
private String sendCommandToProcessingEngine(String command, String param) {
String response = null;
if(!_socket.isConnected()) {
this.init();
}
System.out.println("send '"+command+"("+param+")'");
_send.write(command+" "+param);
try {
response = _receive.readLine();
System.out.println(command+"("+param+"):"+response);
return response;
} catch (IOException e2) {
e2.printStackTrace();
}
return response;
}
public static void main(String[] args) {
DownloadServiceImpl service = new DownloadServiceImpl();
service.reprocessDownload(0);
}
}
As you will see in the code, there are a couple of sys.outs to indicate when the program is attempting to send/receive data.
The output generated:
send 'Logon(null)'
Logon(null):Welcome to MidWare server
send 'ping(null)'
So Java is connecting to the server ok to get the "Welcome to Midware" message back, but when I try to send a command ('ping') I don't get a response.
So the questions:
- does the Java look about right?
- could problem be related to character encoding (Java -> windows)?
You need to flush the output stream:
_send.write(command+" "+param+"\n"); // Don't forget new line here!
_send.flush();
or, since you create a auto-flushing PrintWriter:
_send.println(command+" "+param);
The latter has the disadvantage that the line end can be \n or \r\n, depending on the system on which your Java VM runs. So I prefer the first solution.

Read an AMF object with flex socket

I'm currently trying to communicate between java and flex by using sockets and AMF serialized objects.
On the java side I use Amf3Input and Amf3Output from BlazeDS (flex-messaging-common.jar and flex-messaging-core.jar).
The connection is correctly established, and if i try to send object from flex to java, i can easily read objects :
FLEX side :
protected function button2_clickHandler(event:MouseEvent):void
{
var tmp:FlexAck = new FlexAck;
tmp.id="123456789123456789123456789";
tmp.name="A";
tmp.source="Aaaaaa";
tmp.ackGroup=false;
s.writeObject(tmp);
s.flush();
}
JAVA side :
ServerSocket servSoc = new ServerSocket(8888);
Socket s = servSoc.accept();
Amf3Output amf3Output = new Amf3Output(SerializationContext.getSerializationContext());
amf3Output.setOutputStream(s.getOutputStream());
Amf3Input amf3Input = new Amf3Input(SerializationContext.getSerializationContext());
amf3Input.setInputStream(s.getInputStream());
while(true)
{
try
{
Object obj = amf3Input.readObject();
if(obj!=null){
if (obj instanceof AckOrder){
System.out.println(((AckOrder)obj).getId());
}
}
}
catch (Exception e)
{
e.printStackTrace();
break;
}
}
amf3Output.close();
amf3Input.close();
servSoc.close();
In this way it works perfectly, but the problem is to read objects sent from the java side.
The code I use in java is :
for(int i=0;i<10;i++){
ack = new AckOrder(i,"A","B", true);
amf3Output.writeObject(ack);
amf3Output.writeObjectEnd();
amf3Output.flush();
}
I have an handler on ProgressEvent.SOCKET_DATA :
trace((s.readObject() as FlexAck).id);
But I have errors such as :
Error #2030: End of File detected
Error #2006: Index Out of bound
If i add manipulations on ByteArrays, i manage to read the first object, but not the following.
s.readBytes(tmp,tmp.length);
content = clone(tmp);
(content.readObject());
trace("########################## OK OBJECT RECEIVED");
var ack:FlexAck = (tmp.readObject() as FlexAck);
trace("**********************> id = "+ack.id);
I've spent many our trying to find something in several forums etc, but nothing helped.
So if someone could help me it would be great.
Thanks
Sylvain
EDIT :
Here is an example that I thought should work, but doesn't I hope that it's better illustrate what I aim to do (permanent connection with socket and an exchange of messages).
Java class :
import java.net.ServerSocket;
import java.net.Socket;
import awl.oscare.protocol.AckOrder;
import flex.messaging.io.SerializationContext;
import flex.messaging.io.amf.Amf3Input;
import flex.messaging.io.amf.Amf3Output;
public class Main {
public static void main(String[] args) {
while(true)
{
try {
ServerSocket servSoc = new ServerSocket(8888);
Socket s = servSoc.accept();
System.out.println("connection accepted");
Amf3Output amf3Output = new Amf3Output(SerializationContext.getSerializationContext());
amf3Output.setOutputStream(s.getOutputStream());
Amf3Input amf3Input = new Amf3Input(SerializationContext.getSerializationContext());
amf3Input.setInputStream(s.getInputStream());
while(true)
{
try
{
System.out.println("Reading object");
Object obj = amf3Input.readObject();
if(obj!=null)
{
System.out.println(obj.getClass());
if (obj instanceof AckOrder)
{
AckOrder order = new AckOrder();
order.setId(((AckOrder)obj).getId());
order.setName(((AckOrder)obj).getName());
order.setSource(((AckOrder)obj).getSource());
order.setAckGroup(((AckOrder)obj).isAckGroup());
System.out.println(((AckOrder)obj).getId());
amf3Output.writeObject(order);
amf3Output.writeObjectEnd();
amf3Output.flush();
}
}
}
catch (Exception e)
{
e.printStackTrace();
break;
}
}
amf3Output.close();
amf3Input.close();
servSoc.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
Java Serializable object :
package protocol;
import java.io.Serializable;
public class AckOrder implements Serializable {
private static final long serialVersionUID = 5106528318894546695L;
private String id;
private String name;
private String source;
private boolean ackGroup = false;
public String getId() {
return this.id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public void setSource(String source) {
this.source = source;
}
public String getSource() {
return this.source;
}
public void setAckGroup(boolean ackGroup) {
this.ackGroup = ackGroup;
}
public boolean isAckGroup() {
return this.ackGroup;
}
public AckOrder()
{
super();
}
}
Flex Side :
Main flex code :
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.controls.Alert;
import mx.events.FlexEvent;
import mx.utils.object_proxy;
private var _socket:Socket = new Socket();;
private function onCreationComplete():void
{
this._socket.connect("localhost",8888);
this._socket.addEventListener(ProgressEvent.SOCKET_DATA, onData);
}
private function onData(e:ProgressEvent):void
{
if(this._socket.bytesAvailable)
{
this._socket.endian = Endian.LITTLE_ENDIAN;
var objects:Array = [];
try{
while(this._socket.bytesAvailable > 0)
{
objects.push(this._socket.readObject());
}
}catch(e:Error){trace(e.message);}
trace("|"+(objects)+"|");
}
}
protected function sendButton_clickHandler(event:MouseEvent):void
{
var tmp:FlexAck = new FlexAck;
tmp.id="1";
tmp.name="A";
tmp.source="B";
tmp.ackGroup=false;
this._socket.writeObject(tmp);
this._socket.flush();
}
]]>
</fx:Script>
<s:Button x="0" y="0" name="send" label="Send" click="sendButton_clickHandler(event)"/>
Flex serializable object :
package
{
[Bindable]
[RemoteClass(alias="protocol.AckOrder")]
public class FlexAck
{
public function FlexAck()
{
}
public var id:String;
public var name:String;
public var source:String;
public var ackGroup:Boolean;
}
}
Edit 25/05/2011 :
I've added those listeners in my flex code :
this._socket.addEventListener(Event.ACTIVATE,onActivate);
this._socket.addEventListener(Event.CLOSE,onClose);
this._socket.addEventListener(Event.CONNECT,onConnect);
this._socket.addEventListener(Event.DEACTIVATE,onDeactivate);
this._socket.addEventListener(IOErrorEvent.IO_ERROR,onIOerror);
this._socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR,onSecurityError);
But There's no errors and I still don't manage to receive objects correctly.
You have to send the AMF data as ByteArray on the server:
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
amf3Output.setOutputStream(baos);
amf3Output.writeObject(order);
amf3Output.flush();
amf3Output.close();
s.getOutputStream().write(baos.toByteArray());
Then
this._socket.readObject()
works as expected !
Hi the problem is caused by the following:
An AMF stream is stateful. When it serializes objects, it compresses them relative to objects that it have already been written.
Compression is achieved by referencing previously sent class descriptions, string values and objects using indexes (so for example, if the first string you sent was "heloWorld", when you later send that string, the AMF stream will sent string index 0).
Unfortunately, ByteArray and Socket do not maintain reference tables between readObject calls. Thus, even if you keep appending your newly read objects to the end of the same ByteArray object, each call to readObject instantiates new reference tables, discarding previously created ones (this means it should work for repeated references to the same string within an object tree)
In your example, you are always writing the same string values to properties. Thus when you send the second object, its string properties are not serialized as strings, but as references to the strings in the previously written object.
The solution, is to create a new AMF stream for each object you send.
This is complete rubbish of course(!) It means we can't really utilize the compression in custom protocols. It would be much better if our protocols could decide when to reset the these reference tables, perhaps when they got too big.
For example, if you have an RPC protocol, it would be nice to have an AMF stream pass the remote method names as references rather than strings for speed...
I haven't checked but I think this sort of thing is done by RTMP. The reason it probably wouldn't have been made available in developer objects like ByteArray and Socket (sigh, I hope this isn't true) is because Adobe wants to push us towards LCDS...
Addendum/edit: just found this, which provides a solution http://code.google.com/p/cvlib/
After looking at the code, I think what you want to do on the Java end is this:
for(int i=0;i<10;i++){
ack = new AckOrder(i,"A","B", true);
amf3Output.writeObject(ack);
}
amf3Output.flush();
When you do 'flush', you're sending information over the socket so you only had one object being sent at a time. On the Flex end, you should always try to see what's the length of the object and make sure you're not going over it which would cause this error.
EDIT:
private var _socket:Socket = new Socket();
private function onCreationComplete():void
{
// Add connection socket info here
this._socket.addEventListener(ProgressEvent.SOCKET_DATA, onData);
}
// This gets called every time we get new info, as in after the server flushes
private function onData(e:ProgressEvent):void
{
if(this._socket.bytesAvailable)
{
this._socket.endian = Endian.LITTLE_ENDIAN; // Might not be needed, but often is
// Try to get objects
var objects:Array = [];
try{
while(this._socket.bytesAvailable > 0)
{
objects.push(this._socket.readObject());
}
}catch(e:Error){}
// Do something with objects array
}
}
The onData function is called continually (every time the server sends info) since everything is asynchronous.

Categories

Resources