[Из песочницы] Передаем больше 40 килобайт по LocalConnection

С ростом Flash проекта состоящего из раздельных .swf, соединенных между собой через LocalConnection, может возрасти потребность в размерах передаваемых данных. К примеру, это может быть обмен данными присланных сообщений между игрой и отдельным приложением сообщений.Проблемы начинаются когда передаваемых данных становится больше 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 final 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 — принятые данные. */ private 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 { /** Максимальный размер блока данных*/ public static const BLOCK_WEIGHT: uint = 40000; private var _complete: Boolean = true; public function ExtendedLocalConnect () { super (); } /** * Метод отправки данных. * @param localConnectionName — имя подключения; * @param args — аргументы, первым должено идти название вызываемого метода. */ public final function write (localConnectionName: String, … args): void { _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 > BLOCK_WEIGHT)? BLOCK_WEIGHT: currentLength; var packet: ByteArray = new ByteArray (); // Формируем пакет данных bytes.readBytes (packet, 0, packageLength); currentPosition += packageLength; currentLength = bytesLength — currentPosition; if (! currentLength) _complete = true; // Отправляем пакет send (localConnectionName, «reciverLocalConnection», 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); e4de553dea194dbba54c670126ebcff8.pngРезультат работы приемника

66b722fa5a004f569ca56623b9f49786.pngРезультат отправки объекта

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

© Habrahabr.ru