Limit to ByteArray length?
sneakyimp Apr 16, 2009 3:02 PMOK 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



