bytesAvailable,readUTF()和ProgressEvent.SOCKET_DATA

时间:2010-02-23 12:35:52

标签: flash actionscript-3 sockets

我有一个多人游戏,它从服务器读取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 个答案:

答案 0 :(得分:2)

我想,我找到了解决方案。 由于TCP性质,可能存在两个问题:

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 :(得分:1)

所有socket.read*方法都可能会抛出EOFErrorIOError,因此请务必抓住它们。它可能就是这么简单吗?

另一个想法是,readUTF()调用假定前两个字节(一个短)应该包含UTF字符串的字节长度。如果您的perl服务器没有发送该长度,则可能是readUTF()调用将第一个UTF 字符解释为字节长度,因此最终等待更多数据从未到达。

尝试使用:

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

除此之外,你真的需要能够重现这个问题,或者你很难知道你是否已经修复了它。