[Flashcoders] bytesAvailable, readUTF() and ProgressEvent.SOCKET_DATA
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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