📜 ⬆️ ⬇️

Passing more than 40 kilobytes via LocalConnection

With the growth of the Flash project consisting of separate .swf interconnected through LocalConnection, the need for the size of the transmitted data may increase. For example, this may be the exchange of data sent messages between the game and a separate application messages.

Problems begin when the transferred data becomes more than 40 KB, an error appears and the application stops working normally.

I recall that the amount of data that can be transmitted as parameters by the send method is limited to 40 kilobytes.
')
There are several ways out of this situation:
  1. Use Local Shared Objects;
  2. Transfer data using javascript;
  3. Transmit data by breaking LocalConnection.


The first two items require more changes than the last. Therefore, with minimal cost, we realize the transfer of data in parts that will be less than 40 Kb.

The structure of the transmitted data:
  1. unsigned int - data length of the entire message;
  2. unsigned int - the length of the object data;
  3. data of the serialized object.


To collect all the data correctly, we will write a wrapper for the LocalConnection client:
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); } } } 

Next, we extend the standard LocalConnection class, we will transfer data based on the size of all arguments passed to the send method:

 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; } } 


Let me explain why the complete property is needed. Each time the data is sent, the send method raises a StatusEvent.STATUS event. In our case, a single message can create many such events, so to determine that the message was sent, we write the state to complete.
Usage example:
 var extendedLocalConnection:ExtendedLocalConnect = new ExtendedLocalConnect(); var client:ExtendedClient = new ExtendedClient(this); extendedLocalConnection.target = client; //   extendedLocalConnection.connect("myConnection"); //   extendedLocalConnection.write("myConnection", "myFunction", data); 



The result of the receiver


The result of sending the object

Thus, we can easily replace the standard LocalConnection and bypass the restriction on data transfer. And in the case when it is necessary to use standard data transfer methods, you can extend the ExtendedClient class and describe additional calling methods.
UPD: added automatic detection of the available block size depending on the name of the connection and the name of the method being called. Thanks for the simbiod care.

Source: https://habr.com/ru/post/246119/


All Articles