bytesAvailable, readUTF () и ProgressEvent.SOCKET_DATA - PullRequest
1 голос
/ 23 февраля 2010

У меня есть многопользовательская игра, которая читает данные XML с сервера:

 _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);
  }
}

В большинстве случаев это работает нормально, но иногда пользователи жалуются, что игра зависает для них.Они могут отправлять команды на сервер, но из их описаний я подозреваю, что приведенная выше функция не работает для них, и updateGUI() перестает вызываться.

Эта проблема трудна для отладки... Я думаю, что мой сервер (в Perl / C, не разветвленный, использует poll ()) работает хорошо, я должен делать что-то не так со стороны Flash.

Это хорошая идея для вызова readUTF() здесь?Вполне может случиться так, что только часть строки UTF прибудет, и тогда фильм Flash остановится в readUTF(), не так ли?(Я никогда этого не видел)

ОБНОВЛЕНИЕ:

Да, спасибо, мне нужно поймать EOFError, также у меня есть хороший совет всписок рассылки, который я должен прочитать _socket.bytesAvailable байт в ByteArray и работать с этим (проверьте, пришло ли мое полное сообщение) - все остальное ненадежно.

Так что я придумал это, но все жеесть недостаток:

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;
       }
}
  • , когда доступно слишком много байтов, например, 800, а мои сообщения имеют длину только 400 байтов, то он застревает.

Также мне интересно, можно ли улучшить копирование оставшихся байтов (то есть, не выделяя каждый раз новый ByteArray)?

Я могу воспроизводить этот недостаток часто, к счастью

Ответы [ 2 ]

2 голосов
/ 24 февраля 2010

Я думаю, я нашел решение. Из-за TCP-природы могут возникнуть 2 проблемных случая:

1) несколько UTF-строк с префиксами поступают одновременно 2) приходит неполная UTF-строка с префиксом

Этот код должен обрабатывать оба:

private function handleTcpData(event:Event):void {
// CASE 1, JUST KEEP EXTRACTING UTF-STRINGS
 while(_socket.bytesAvailable) {
 try{
   var str:String = _socket.readUTF();
   updateGUI(str);
  }catch(e:Error){
    // CASE 2 INCOMPLETE STRING,
    // WILL BE READ BY LATER handleTcpData CALL
    return;
  }
 }
}

Кроме того, в моем исходном коде я неправильно копировал ByteArray. Я должен иметь:

var newBA:ByteArray = new ByteArray();
_ba.readBytes(newBA);
_ba = newBA;

или даже сделать это на месте, не создавая newBA.

1 голос
/ 23 февраля 2010

Все socket.read* методы могут выдавать EOFError и IOError, поэтому убедитесь, что вы их ловите. Это может быть что-то так просто?

Другая мысль, вызов readUTF() предполагает, что первые два байта (короткий) должны содержать длину в байтах строки UTF. Если ваш сервер Perl не отправляет эту длину, возможно, вызов readUTF() интерпретирует первый UTF символ как длину байта и, таким образом, в конечном итоге ожидает больше данных, которые никогда не поступают.

Попробуйте использовать:

  var str:String = _socket.readUTFBytes(_socket.bytesAvailable);

Кроме этого, вам действительно нужно иметь возможность воспроизвести проблему, или совершенно невозможно узнать, исправили ли вы ее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...