[Flashcoders] bytesAvailable, readUTF() and ProgressEvent.SOCKET_DATA

2010-02-23 Thread Alexander Farber
Hello,

I have multiplayer game, which reads XML data from the server:

  _socket = new Socket();
  _socket.addEventListener(ProgressEvent.SOCKET_DATA, handleTcpData);
.
private function handleTcpData(event:Event):void {
   while (_socket.bytesAvailable) {
  var str:String = _socket.readUTF();
  updateGUI(str);
   }
}

In most cases it works ok, but sometimes users complain that
the game hangs for them. They are able to send in commands to
the server, but from their descriptions I suspect, that the function
above doesn't work well for them and the updateGUI() stops being called.

This issue is difficult to debug... I think my server (in Perl/C,
non-forking, uses poll()) works well, I must be doing something
wrong at the Flash side.

Is it a good idea to call readUTF() here? It could well be that
only part of the UTF string arrives and then the Flash movie
would freeze in readUTF(), wouldn't it? (I've never seen that though)

Regards
Alex
___
Flashcoders mailing list
Flashcoders@chattyfig.figleaf.com
http://chattyfig.figleaf.com/mailman/listinfo/flashcoders


Re: [Flashcoders] bytesAvailable, readUTF() and ProgressEvent.SOCKET_DATA

2010-02-23 Thread Henrik Andersson
Doing anything but copying the data from the event to your own bytearray 
buffer object is a disaster waiting to happen.


TCP is a stream based protocol, you can get chunks of any length each 
time the event is reviced. Assume that the chunks are random length and 
piece them together in a buffer of your own. Then, once you know that 
you have a full logical unit, process the data.

___
Flashcoders mailing list
Flashcoders@chattyfig.figleaf.com
http://chattyfig.figleaf.com/mailman/listinfo/flashcoders


Re: [Flashcoders] bytesAvailable, readUTF() and ProgressEvent.SOCKET_DATA

2010-02-23 Thread Alexander Farber
Hello,

On Tue, Feb 23, 2010 at 2:25 PM, Henrik Andersson he...@henke37.cjb.net wrote:
 Doing anything but copying the data from the event to your own bytearray
 buffer object is a disaster waiting to happen.

 TCP is a stream based protocol, you can get chunks of any length each time
 the event is reviced. Assume that the chunks are random length and piece
 them together in a buffer of your own. Then, once you know that you have a
 full logical unit, process the data.

I agree with you (from my Perl/C experience)
and will switch to using ByteArray:

_socket.readBytes(myByteArray, offset, _socket.bytesAvailable);

Or maybe I'll start using XMLSocket (is that one safe?)

The only thing I don't understand is why does ActionScript API
offer a function like readUTF() if it can't be used at all?

Regards
Alex
___
Flashcoders mailing list
Flashcoders@chattyfig.figleaf.com
http://chattyfig.figleaf.com/mailman/listinfo/flashcoders


Re: [Flashcoders] bytesAvailable, readUTF() and ProgressEvent.SOCKET_DATA

2010-02-23 Thread Valentin Schmidt

 private function handleTcpData(event:Event):void {
while (_socket.bytesAvailable) {
   var str:String = _socket.readUTF();
   updateGUI(str);
}
 }

maybe you shouldn't ignore thrown errors: AFAIK if the UTF8-data is not
complete (ie.. the last UTF-8 byte sequence is truncated), readUTF()
will throw an EOFError error. so if you handle this error correctly, you
might be safe?

cheers,
valentin
___
Flashcoders mailing list
Flashcoders@chattyfig.figleaf.com
http://chattyfig.figleaf.com/mailman/listinfo/flashcoders


Re: [Flashcoders] bytesAvailable, readUTF() and ProgressEvent.SOCKET_DATA

2010-02-23 Thread Alexander Farber
I've come up with this, but still have a flaw there:

private function handleTcpData(event:Event):void {
var len:uint;

if (0 == _socket.bytesAvailable)
return;

try {
_socket.readBytes(_ba, _ba.bytesAvailable, 
_socket.bytesAvailable);

// read the length of the UTF string to follow
while (_ba.bytesAvailable = 2) {
len = _ba.readUnsignedShort();

// invalid length - reset
if (0 == len) {
trace('XXX invalid len = ' + len);
_ba.position = 0;
_ba.length = 0;
return;
}

if (_ba.bytesAvailable = len) {
var str:String = _ba.readUTFBytes(len);
updateGUI(str);

// copy the remaining bytes
// (does it work? can it be improved?)
var newBA:ByteArray = new ByteArray();
newBA.readBytes(_ba);
_ba = newBA;
}
}
} catch(e:Error) {
trace('XXX ' + e);
_ba.position = 0;
_ba.length = 0;
return;
}
}

- when there are too many bytes available, for example 800
and my messages are only 400 bytes long, then it stucks.

Also I wonder, if copying remaining bytes could be
improved (i.e. without allocating a new ByteArray each time)?

Regards
Alex
___
Flashcoders mailing list
Flashcoders@chattyfig.figleaf.com
http://chattyfig.figleaf.com/mailman/listinfo/flashcoders


Re: [Flashcoders] bytesAvailable, readUTF() and ProgressEvent.SOCKET_DATA

2010-02-23 Thread Alexander Farber
I've added some traces there and see that this doesn't work:

   if (_ba.bytesAvailable = len) {
   var str:String = _ba.readUTFBytes(len);
   updateGUI(str);

   // copy the remaining bytes
   // (does it work? can it be improved?)
   var newBA:ByteArray = new ByteArray();
   newBA.readBytes(_ba);
   _ba = newBA;
   }

- the newBA.length stays zero.

Please help me with this little bit.

My problem is that when I read many bytes into my _ba
(i.e. if I read several messages at once) and then
process one message (with the updateGUI() above),
how do I get rid of those processed bytes?

I suppose I must somehow cut those processed
bytes away from the beginning of the _ba,
that is why I introduced copying into a newBA above,
but this doesn't work.

Regards
Alex
___
Flashcoders mailing list
Flashcoders@chattyfig.figleaf.com
http://chattyfig.figleaf.com/mailman/listinfo/flashcoders


Re: [Flashcoders] bytesAvailable, readUTF() and ProgressEvent.SOCKET_DATA

2010-02-23 Thread Valentin Schmidt
Alexander Farber wrote:
 I've come up with this, but still have a flaw there:
 
 private function handleTcpData(event:Event):void {
   var len:uint;

what about this simple alternative:

private function handleTcpData(event:Event):void {
  if(_socket.bytesAvailable) {
try{
  var str:String = _socket.readUTF();
  updateGUI(str);
}catch(e:Error){}
  }
}


I havn't tested, but if the socket class is well designed, the buffer
should only be flushed if readUTF() was sucessful, and therefor the
above code should work fine.

cheers,
valentin
___
Flashcoders mailing list
Flashcoders@chattyfig.figleaf.com
http://chattyfig.figleaf.com/mailman/listinfo/flashcoders


Re: [Flashcoders] bytesAvailable, readUTF() and ProgressEvent.SOCKET_DATA

2010-02-23 Thread Alexander Farber
Yes, that's with what I had started and what doesn't work :-)

On Tue, Feb 23, 2010 at 11:17 PM, Valentin Schmidt v...@dasdeck.com wrote:
 private function handleTcpData(event:Event):void {
  if(_socket.bytesAvailable) {
    try{
      var str:String = _socket.readUTF();
      updateGUI(str);
    }catch(e:Error){}
  }
 }


___
Flashcoders mailing list
Flashcoders@chattyfig.figleaf.com
http://chattyfig.figleaf.com/mailman/listinfo/flashcoders


Re: [Flashcoders] bytesAvailable, readUTF() and ProgressEvent.SOCKET_DATA

2010-02-23 Thread Valentin Schmidt
Alexander Farber wrote:
 Yes, that's with what I had started and what doesn't work :-)

so then why did you start with posting code here (pasted below) that
didn't contain any exception catching? that's the crucial point: you
have to catch the exception, otherwise you would either get corrupted
UTF strings or and be caught in an infinite loop (because you used
while instead of if!).

here the code you had posted (that is quite different to mine):

  _socket = new Socket();
  _socket.addEventListener(ProgressEvent.SOCKET_DATA, handleTcpData);
.
private function handleTcpData(event:Event):void {
   while (_socket.bytesAvailable) {
  var str:String = _socket.readUTF();
  updateGUI(str);
   }
}

cheers,
valentin
___
Flashcoders mailing list
Flashcoders@chattyfig.figleaf.com
http://chattyfig.figleaf.com/mailman/listinfo/flashcoders


Re: [Flashcoders] bytesAvailable, readUTF() and ProgressEvent.SOCKET_DATA

2010-02-23 Thread Valentin Schmidt
some comments added to make it easier for you to spot the differences :-)

private function handleTcpData(event:Event):void {
  if(_socket.bytesAvailable) { // USE IF, NOT WHILE!
try{ // CATCH THE EXCEPTION
  var str:String = _socket.readUTF();
  updateGUI(str);
}catch(e:Error){}
  }
}
___
Flashcoders mailing list
Flashcoders@chattyfig.figleaf.com
http://chattyfig.figleaf.com/mailman/listinfo/flashcoders


Re: [Flashcoders] bytesAvailable, readUTF() and ProgressEvent.SOCKET_DATA

2010-02-23 Thread Alexander Farber
Hello Valentin,

On Wed, Feb 24, 2010 at 12:06 AM, Valentin Schmidt v...@dasdeck.com wrote:
 so then why did you start with posting code here (pasted below) that
 didn't contain any exception catching? that's the crucial point: you
 have to catch the exception, otherwise you would either get corrupted
 UTF strings or and be caught in an infinite loop (because you used
 while instead of if!).


yes, I did try catching the exceptions.
In fact that is the code running at my site
( http://apps.facebook.com/video-preferans/ )
right now and it still doesn't work.

The try/catch won't help here.

And if you use an if instead of while,
then you lose even more incoming data.

Regards
Alex
___
Flashcoders mailing list
Flashcoders@chattyfig.figleaf.com
http://chattyfig.figleaf.com/mailman/listinfo/flashcoders


Re: [Flashcoders] bytesAvailable, readUTF() and ProgressEvent.SOCKET_DATA

2010-02-23 Thread Valentin Schmidt
 And if you use an if instead of while,
 then you lose even more incoming data.

how come?
___
Flashcoders mailing list
Flashcoders@chattyfig.figleaf.com
http://chattyfig.figleaf.com/mailman/listinfo/flashcoders


Re: [Flashcoders] bytesAvailable, readUTF() and ProgressEvent.SOCKET_DATA

2010-02-23 Thread Alexander Farber
On Wed, Feb 24, 2010 at 12:36 AM, Valentin Schmidt v...@dasdeck.com wrote:
 And if you use an if instead of while,
 then you lose even more incoming data.

 how come?

Ok, here your suggestion again:

private function handleTcpData(event:Event):void {
 if(_socket.bytesAvailable) { // USE IF, NOT WHILE!
   try{ // CATCH THE EXCEPTION
 var str:String = _socket.readUTF();
 updateGUI(str);
   }catch(e:Error){}
 }
}

The problem is that you read an UTF string with prefixed length just once.

But since it's TCP sockets, data can arrive in different amounts.

And in fact I see that sometimes not just one,
but several UTF strings with prefix will arrive.

But your if-code will process just the 1st one.

And another problem with that code:
if a half of a string arrives, then it will throw an EOFError,
then go into the empty catch branch and just lose that data.

Regards
Alex
___
Flashcoders mailing list
Flashcoders@chattyfig.figleaf.com
http://chattyfig.figleaf.com/mailman/listinfo/flashcoders


Re: [Flashcoders] bytesAvailable, readUTF() and ProgressEvent.SOCKET_DATA

2010-02-23 Thread Alexander Farber
After some thought... the 2nd case (not enough data arrived)
is not a problem for your code, because the handleTcpData()
will get called again - once the rest of the data arrived.

But for the 1st case (several UTF strings arrived at once)...
Maybe I should try the following (and don't need a ByteArray):

private function handleTcpData(event:Event):void {
// KEEP EXTRACTING UTF-STRINGS
 while(_socket.bytesAvailable) {
  try{
var str:String = _socket.readUTF();
updateGUI(str);
   }catch(e:Error){
 // INCOMPLETE STRING, WILL BE READ LATER
 return;
   }
 }
}
___
Flashcoders mailing list
Flashcoders@chattyfig.figleaf.com
http://chattyfig.figleaf.com/mailman/listinfo/flashcoders


Re: [Flashcoders] bytesAvailable, readUTF() and ProgressEvent.SOCKET_DATA

2010-02-23 Thread Valentin Schmidt
Alexander Farber wrote:
 After some thought... the 2nd case (not enough data arrived)
 is not a problem for your code, because the handleTcpData()
 will get called again - once the rest of the data arrived.
 
 But for the 1st case (several UTF strings arrived at once)...
 Maybe I should try the following (and don't need a ByteArray):
 
 private function handleTcpData(event:Event):void {
 // KEEP EXTRACTING UTF-STRINGS
  while(_socket.bytesAvailable) {
   try{
 var str:String = _socket.readUTF();
 updateGUI(str);
}catch(e:Error){
  // INCOMPLETE STRING, WILL BE READ LATER
  return;
}
  }
 }

yes, I think that might be a good idea: the problem I saw peviously was
that if bytesAvailable0, but for some reason the try-statement fails
(and therefor bytesAvailable isn't set to 0), you would be caught in an
infinite loop, because I don't think the socket data will be updated
from outside while you are inside such an endless repeat-loop.

but by adding this return statement that leaves the loop this can't
happen anymore. good luck :-)

cheers,
valentin
___
Flashcoders mailing list
Flashcoders@chattyfig.figleaf.com
http://chattyfig.figleaf.com/mailman/listinfo/flashcoders