С ростом Flash проекта состоящего из раздельных .swf, соединенных между собой через LocalConnection, может возрасти потребность в размерах передаваемых данных. К примеру, это может быть обмен данными присланных сообщений между игрой и отдельным приложением сообщений.
Проблемы начинаются когда передаваемых данных становится больше 40 Кб, появляется ошибка и приложение перестает нормально работать.
Напомню, что объем данных, которые можно передать как параметры методом send, ограничен 40 килобайтами.
Есть несколько выходов из такой ситуации:
Первые два пункта требуют больших изменений чем последний. Поэтому с минимальными затратами реализуем передачу данных по частям которые будут меньше 40 Кб.
Структура передаваемых данных:
Что бы правильно собрать все данные напишем обертку для клиента LocalConnection:
Дальше расширяем стандартный класс LocalConnection, передачу данных будем осуществлять с учетом, размера всех аргументов передаваемых в метод send:
Поясню зачем нужно свойство complete, при каждой отправке данных метод send создает событие StatusEvent.STATUS. В нашем случае одно сообщение может создавать много таких событий, поэтому что бы определить что сообщение отправлено мы записываем состояние в complete.
Пример использования:

Результат работы приемника

Результат отправки объекта
Таким образом мы можем легко заменить стандартный LocalConnection и обойти ограничение на передачу данных. А в случае когда необходимо использовать и стандартные методы передачи данных, то можно расширить класс ExtendedClient и описать дополнительные методы вызова.
UPD: добавлено автоматическое определение доступного размера блока в зависимости от имени соединения и имени вызываемого метода.Спасибо за внимательность simbiod.
Проблемы начинаются когда передаваемых данных становится больше 40 Кб, появляется ошибка и приложение перестает нормально работать.
Напомню, что объем данных, которые можно передать как параметры методом send, ограничен 40 килобайтами.
Есть несколько выходов из такой ситуации:
- Использовать Local Shared Objects;
- Передавать данные с помощью JavaScript;
- Передавать данные по LocalConnection разбив на части.
Первые два пункта требуют больших изменений чем последний. Поэтому с минимальными затратами реализуем передачу данных по частям которые будут меньше 40 Кб.
Структура передаваемых данных:
- unsigned int — длина данных всего сообщения;
- unsigned int — длина данных объекта;
- данные сериализованного объекта.
Что бы правильно собрать все данные напишем обертку для клиента LocalConnection:
public class ExtendedClient { private var receivedData:ByteArray = new ByteArray(); private var length:int = -1; /** Пользовательский класс - обработчик*/ private var client:Object; public function ExtendedClient(client:Object) { this.client = client; } /** * Метод удаленного вызова. * @param packet - входящие данные. */ public function reciverLocalConnection(packet:ByteArray):void { // Читаем длину всего сообщения if(length == -1) length = packet.readUnsignedInt(); packet.readBytes(receivedData, receivedData.length, packet.length - packet.position); // Если необходимое количество данных принять if(receivedData.length == length) { // Обрабатываем полученные данные deserialization(receivedData); receivedData = new ByteArray(); length = -1; } } /** * Десериализаия данных. * @param receivedData - принятые данные. */ protected function deserialization(receivedData:ByteArray):void { var parameters:Array = new Array(); var temp:ByteArray = new ByteArray(); while(receivedData.position != receivedData.length) { receivedData.readBytes(temp, 0, receivedData.readUnsignedInt() - 4); parameters.push(temp.readObject()); temp.clear(); } try { // Отправляем данные в запрашиваемый мтод (client[parameters[0]] as Function).apply(this, parameters.slice(1)); }catch(error:ReferenceError) { trace("Error:", error.message); } } }
Дальше расширяем стандартный класс LocalConnection, передачу данных будем осуществлять с учетом, размера всех аргументов передаваемых в метод send:
public class ExtendedLocalConnect extends LocalConnection { private static const METHOD_NAME:String = "reciverLocalConnection"; /** Максимальный размер блока данных*/ private var _blockWeight:int; private var _complete:Boolean = true; public function ExtendedLocalConnect() { super(); } /** * Метод отправки данных. * @param localConnectionName - имя подключения. * @param args - аргументы, первым должено идти название вызываемого метода. */ public function write(localConnectionName:String, ... args):void { // 63 байта занимает дополнительная информация необходимая для передачи данных _blockWeight = 40897 - localConnectionName.length - METHOD_NAME.length; _complete = false; var bytes:ByteArray = new ByteArray(); // Оставляем место для длины данных сообщения bytes.writeUnsignedInt(0); // Сериализуем все аргументы for(var i:int = 0, n:int = args.length; i < n; i++) { var startPosition:int = bytes.position; bytes.writeUnsignedInt(0); bytes.writeObject(args[i]); bytes.position = startPosition; // Записываем длину данных объекта bytes.writeUnsignedInt(bytes.length - startPosition); bytes.position = bytes.length; } bytes.position = 0; //Записываем длину данных сообщения bytes.writeUnsignedInt(bytes.length - 4); bytes.position = 0; var bytesLength:int = bytes.length; var currentPosition:int = 0; var currentLength:int = bytesLength; while(currentLength > 0) { var packageLength:int = (currentLength > _blockWeight)? _blockWeight: currentLength; var packet:ByteArray = new ByteArray(); // Формируем пакет данных bytes.readBytes(packet, 0, packageLength); currentPosition += packageLength; currentLength = bytesLength - currentPosition; if(!currentLength) _complete = true; // Отправляем пакет send(localConnectionName, METHOD_NAME, packet); } bytes.clear(); } public function set target(extendedClient:ExtendedClient):void { client = extendedClient; } public function get complete():Boolean { return _complete; } }
Поясню зачем нужно свойство complete, при каждой отправке данных метод send создает событие StatusEvent.STATUS. В нашем случае одно сообщение может создавать много таких событий, поэтому что бы определить что сообщение отправлено мы записываем состояние в complete.
Пример использования:
var extendedLocalConnection:ExtendedLocalConnect = new ExtendedLocalConnect(); var client:ExtendedClient = new ExtendedClient(this); extendedLocalConnection.target = client; // Для приемника extendedLocalConnection.connect("myConnection"); // Отправка данных extendedLocalConnection.write("myConnection", "myFunction", data);

Результат работы приемника

Результат отправки объекта
Таким образом мы можем легко заменить стандартный LocalConnection и обойти ограничение на передачу данных. А в случае когда необходимо использовать и стандартные методы передачи данных, то можно расширить класс ExtendedClient и описать дополнительные методы вызова.
UPD: добавлено автоматическое определение доступного размера блока в зависимости от имени соединения и имени вызываемого метода.Спасибо за внимательность simbiod.
