2 Replies Latest reply: Apr 16, 2009 6:58 PM by AttaBoy2 RSS

    Limit to ByteArray length?

    sneakyimp Community Member

      OK I am still trying to figure this out.  The idea is pretty simple.

       

      My Flash movie has connected to a server via Socket.  The server has sent some data over the Socket connection.  This data consists of a 4-byte message header which describes the length of the incoming message and then the message itself.  In this particular case, my message has a length of 500040 bytes.

       

      My code receives the first installment of this long socket message in a block of 4,380 bytes. I know this because of trace statements in my socketDataHandler function.  It peels off the 4 bytes at the beginning and interprets them to get the incoming message length of 500040.  The remaining 4376 bytes go into a ByteArray var (a property of my class) called buffer.  As more blocks of data arrive, the socketDataHandler function is repeatedly triggered and the extra blocks are concatenated into the buffer.

       

      The problem happens when the buffer ByteArray reaches a length of 131396.  For some reason, once this length is reached, the buffer cannot hold any more data and the socketDataHandler events stop.

       

      Is this a limitation of the ByteArray object's size?  Does it have something to do with the Socket data type?  Does anyone know?

      Here's the code:

      private function socketDataHandler(evt:ProgressEvent):void {
      trace('socketdatahandler');
                  var tmpBuf:ByteArray;
                  var messageBytes:ByteArray;
                 
                  log.write('RPCSocket.socketDataHandler invoked:' +  evt, Log.LOW);

                  var bytesAvail:int = super.bytesAvailable;
      trace('bytesAvail:' + bytesAvail);
      trace('buffer length:' + buffer.length);           
                  var totalLength:int = buffer.length + bytesAvail;
                  if (totalLength > RPCSocket.MAX_BUFFER_LENGTH) {
                      // read all the socket data and dump it
                      tmpBuf = new ByteArray();
      trace('reading all bytes to empty buffer');
                      super.readBytes(tmpBuf, 0, bytesAvail);
                      tmpBuf = null;

                      resetBuffer();
                      log.write('RPCSocket.socketDataHandler failed.  Buffer length of ' +
      totalLength + ' exceeds maximum allowed of ' + RPCSocket.MAX_BUFFER_LENGTH +
      ' bytes.  Buffer reset.', Log.HIGH);
                      dispatchEvent(new IOErrorEvent(IOErrorEvent.IO_ERROR, false, false,
      'RPCSocket.socketDataHandler failed.  Maximum buffer length of ' + totalLength + ' exceeds
      maximum allowed of '
      + RPCSocket.MAX_BUFFER_LENGTH + ' bytes.  Buffer reset.'));
                      return;
                  }
                 
                  // otherwise, add all the socket's available data to the buffer
      trace('reading bytes into buffer for concat');
                  super.readBytes(buffer, buffer.length);
      trace('buffer length after concat:' + buffer.length);        
                  // try to peel off any messages that might live on the buffer
                  do {
      trace('buffer state:' + bufferState);
                      switch(bufferState) {
                          case RPCSocket.BUFFER_STATE_READY :
      trace('BUFFER state is ready');
                              if (buffer.length < RPCSocket.MESSAGE_LENGTH_INDICATOR_BYTES) {
                                  return; // not enough to do anything yet
                              }
      trace("\tand we got enough bytes: " + buffer.length);
                              // otherwise, we can at least read the incoming message length
                              incomingMessageLength = buffer.readUnsignedInt();
      trace('setting mesg length to ' + incomingMessageLength);
                              // sanity check
                              if (incomingMessageLength == 0) {
      trace('DAMN have to reset buffer');
                                  resetBuffer();
                                  log.write('Incoming message length of zero. Flushing buffer.', Log.HIGH);
                                  return;
                              }
                              bufferState = RPCSocket.BUFFER_STATE_READING;
      trace('buffer state set to ' + RPCSocket.BUFFER_STATE_READING);
                              // NOTE - at this point, the buffer's position has advanced
                              // let's trim those few bytes off the beginning
      trace('trimming 4 bytes off buffer');              
                              tmpBuf = new ByteArray();
                              buffer.readBytes(tmpBuf, 0);
                              buffer = new ByteArray();
                              tmpBuf.readBytes(buffer, 0);
                              tmpBuf = null;
      trace('buffer length:' + buffer.length);
                              break;
                             
                          case RPCSocket.BUFFER_STATE_READING :
                              // nothing to do here...might be some day
                              break;
                          default:
                              resetBuffer();
                              log.write('Unexpected buffer state. Flushing buffer.', Log.HIGH);
                              return;
                      } // switch bufferState
                     
                      if (bufferState == RPCSocket.BUFFER_STATE_READY) {
      trace('buffer state is ready, returning');
                          return;
                      }
      trace('the big check');   
                      if ((bufferState == RPCSocket.BUFFER_STATE_READING) && (buffer.length >= incomingMessageLength)) {
      trace('we in now');
                          // we have our message!  peel it off
                         
                          // read the message's bytes into a new array
                          messageBytes = new ByteArray();
      trace('reading bytes into MessageBytes');
                          buffer.readBytes(messageBytes, 0, incomingMessageLength);
                         
                          // truncate the buffer
      trace('truncating buffer after message bytes out');
                          tmpBuf = new ByteArray();
                          buffer.readBytes(tmpBuf, 0);
                          buffer = new ByteArray();
                          tmpBuf.readBytes(buffer, 0);
      trace('buffer length after trunc:' + buffer.length);
                         
                          // reset the buffer state
                          bufferState = RPCSocket.BUFFER_STATE_READY;
      trace('bufferstate set to ' + bufferState);
                          incomingMessageLength = 0;
                         
                          // unserialize the message and execute the RPC therein
                          var incomingRPC:Array = unserialize(messageBytes);
                          if (!incomingRPC || (!(incomingRPC is Array))) {
                              log.write('RPCSocket.socketDataHandler failed.  Data received
      did not unserialize properly to an array.'
      , Log.HIGH);
                          }
                          var serviceName:String = incomingRPC[0];
                          var eventName:String = incomingRPC[1];
             
                          if (!serviceName) {
                              // no service!  dispatchEvent to all registered services
                              log.write('RPCSocket.socketDataHandler failed.  RPC received
      from server with no serviceName.'
      , Log.HIGH);
                              dispatchEvent(new IOErrorEvent(IOErrorEvent.IO_ERROR,
      false, false, 'RPCSocket.socketDataHandler failed.  RPC received with no serviceName.'));
                              return;
                          }
             
                          var svc:FlashMOGService = services[serviceName];
                          if (!svc) {
                              // service doesn't exist!
                              log.write('RPCSocket.socketDataHandler failed.  No service
      named '
      + serviceName + '.', Log.HIGH);
                              dispatchEvent(new IOErrorEvent(IOErrorEvent.IO_ERROR,
      false, false, 'RPCSocket.socketDataHandler failed.  No service named ' + serviceName + '.'));
                              return;
                          }
                          if (!eventName) {
                              // we have a serviceName but no event name!
                              // broadcast error to that one service only
                              log.write('RPCSocket.socketDataHandler failed.  RPC received
      with no eventName.'
      , Log.HIGH);
                              svc.dispatchEvent(new IOErrorEvent(IOErrorEvent.IO_ERROR,
      false, false, 'RPCSocket.socketDataHandler failed.  RPC received with no eventName.'));
                              return;
                          }
             
                          var args:Array = incomingRPC[2];
                          svc.dispatchEvent(new FlashMOGDataEvent(FlashMOGDataEvent.DATA, false, false, args));
             
                          var methodFunc:Function = services[serviceName].client[eventName];
                          if (methodFunc is Function) {
                              methodFunc.apply(null, args);
                          }
                         
                      } // if bufferState is READ and buffer.length >= incomingMessageLength
      trace ('end of message peel loop');
                  } while ((bufferState == RPCSocket.BUFFER_STATE_READY) &&
      (buffer.length > RPCSocket.MESSAGE_LENGTH_INDICATOR_BYTES));
                 
                  log.write('RPCSocket.socketDataHandler end reached:' +  evt, Log.LOW);
      trace('socket data handler end');
              }// function socketDataHandler()

       

      Here's the trace output:

      socketdatahandler
      bytesAvail:4380
      buffer length:0
      reading bytes into buffer for concat
      buffer length after concat:4380
      buffer state:0
      BUFFER state is ready
      and we got enough bytes: 4380
      setting mesg length to 500040
      buffer state set to 1
      trimming 4 bytes off buffer
      buffer length:4376
      the big check
      end of message peel loop
      socket data handler end
      socketdatahandler
      bytesAvail:8760
      buffer length:4376
      reading bytes into buffer for concat
      buffer length after concat:13136
      buffer state:1
      the big check
      end of message peel loop
      socket data handler end
      socketdatahandler
      bytesAvail:64240
      buffer length:13136
      reading bytes into buffer for concat
      buffer length after concat:77376
      buffer state:1
      the big check
      end of message peel loop
      socket data handler end
      socketdatahandler
      bytesAvail:54020
      buffer length:77376
      reading bytes into buffer for concat
      buffer length after concat:131396
      buffer state:1
      the big check
      end of message peel loop
      socket data handler end