In fact, many cases of communication on Flash are selected.AMF,After all, it is an as internal object-based sequence protocol, with low capacity and high efficiency. But sometimes to call some existing TCP services, and these services do not provide AMF support, then you have to implement a protocol analysis. In fact, as provides many write and read methods for bytearray, which makes our application very convenient. The following is a protocol analyzer that uses the as simple encapsulation Based on the message header Description Size.
To better manage messages, you can use an interface to write and read messages.
Package beetle. As {import flash. utils. bytearray; public interface iMessage {function load (data: reader): void; function save (data: writer): void ;}}
The interface is relatively simple. It is guaranteed to be obtained in the stream and from the stream. Both reader and writer are derived from bytearray objects. Why is bytearray not used directly? The reason is that you can implement more advanced information acquisition methods by yourself.
Package beetle. as {import flash.net. getclassbyalias; import flash. utils. bytearray; import flash. utils. getdefinitionbyname; import MX. controls. image; public class reader extends bytearray {public function reader () {super ();} public function readmessages (classname: string): vector. <iMessage> {var results: vector. <iMessage> = new vector. <iMessage> (); For (var I: Int = 0; I <readint (); I ++) {var MSG: iMessage = iMessage (getdefinitionbyname (classname )); results. push (MSG) ;}return results ;}} package beetle. as {import flash. utils. bytearray; public class writer extends bytearray {public function writer () {super ();} public function writemessages (items: vector. <iMessage>): void {writeint (items. length); For each (VAR item: iMessage in items) {item. save (this );}}}}
After the basic rules are built, we will start to analyze the protocol.
Package beetle. as {import flash.net. socket; import flash. utils. bytearray; import flash. utils. endian; import MX. graphics. shaderclasses. exclusionshader; public class headsizeofpackage {public function headsizeofpackage () {mwriter. endian = endian. little_endian; mreader. endian = endian. little_endian;} private var mmessagereceive: function; // callback function for message receipt public function get messagereceive (): function {return mmessagerec Eive;} public function set messagereceive (value: function): void {mmessagereceive = value;} // The protected function writemessagetag (message: iMessage, data: writer ): void {Throw new error ("writemessagetag not implement! ");} // Obtain the message object protected function getmessagebytag (data: reader): iMessage {Throw new error (" getmessagebytag not implement! ");} Private var mreader: reader = new reader (); Private var msize: Int = 0; // import the data received by the current socket Public Function Import (socket: socket ): void {socket. endian = endian. little_endian; while (socket. bytesavailable> 0) {If (msize = 0) {msize = socket. readint ()-4; mreader. clear ();} If (socket. bytesavailable> = msize) {socket. readbytes (mreader, mreader. length, msize); var MSG: iMessage = getmessagebytag (mreader); MSG. load (mreader ); If (messagereceive! = NULL) messagereceive (MSG); msize = 0;} else {msize = mSize-socket.bytesAvailable; socket. readbytes (mreader, mreader. length, socket. bytesavailable) ;}}} private var mwriter: writer = new writer (); // protocol data encapsulated in payload public function send (message: iMessage, socket: socket ): void {socket. endian = endian. little_endian; mwriter. clear (); writemessagetag (message, mwriter); message. save (mwriter); socket. writeint (mwriter. length + 4); socket. writebytes (mwriter, 0, mwriter. length); socket. flush ();}}}
The implementation of the protocol analyzer is relatively simple. The basic functions include message encapsulation, analysis of the stream, return the source object, and callback the message to the specified function. messagereceive is a function-oriented Attribute used to describe message receiving. Its principle is similar to C # Delegate. The analyzer also has two methods that require the derived classes to override writemessagetag and getmessagebytag. The main function of writemessagetag is to write message type tags and create associated Objects Based on read tag information.
The send method is a protocol packaging process. It processes the information of the object written into the stream and sends it out with the specified socket object.
Public Function send (message: iMessage, socket: socket): void {socket. endian = endian. little_endian; mwriter. clear (); writemessagetag (message, mwriter); message. save (mwriter); socket. writeint (mwriter. length + 4); socket. writebytes (mwriter, 0, mwriter. length); socket. flush ();}
The operation principle is to write the object information to the stream through the Save method of the message interface. The first step is to write the message type mark. The specific writing method is applicable to the string or Int type by the derived class, then, the message content is written. Finally, the header that calculates the length of all data is written to the socket and then the information stream is written.
The import method is a data import task, mainly responsible for reading data from the socket for loading and analysis.
Public Function Import (socket: socket): void {socket. endian = endian. little_endian; while (socket. bytesavailable> 0) {If (msize = 0) {msize = socket. readint ()-4; mreader. clear ();} If (socket. bytesavailable> = msize) {socket. readbytes (mreader, mreader. length, msize); var MSG: iMessage = getmessagebytag (mreader); MSG. load (mreader); If (messagereceive! = NULL) messagereceive (MSG); msize = 0 ;}else {msize = mSize-socket.bytesAvailable; socket. readbytes (mreader, mreader. length, socket. bytesavailable );}}}
The principle is very simple. If the data to be loaded is zero, it indicates a new message for a table. Read the length of the data to be loaded for the message and then read the data from the socket and write it into the stream, when the read length is the same as the current message length, load the message and call back the message to the specific working method through the callback function.
Here, a message analyzer described in the first 4 bytes is completed. This analyzer is used directly. A new analyzer is derived and message tag processing is implemented based on actual needs.
Public class headsizepackage extends headsizeofpackage {public function headsizepackage () {super () ;}override protected function getmessagebytag (data: reader): iMessage {var name: String = data. readutf (); Switch (name) {Case "register": return new register (); Case "user": return new user (); Case "getuser ": return new getuser (); default: return NULL ;}} override protected function writemessagetag (message: iMessage, data: writer): void {If (message is register) {data. writeutf ("register");} else if (message is user) {data. writeutf ("user");} else if (message is getuser) {data. writeutf ("getuser");} else {data. writeutf ("null ");}}}
The implementation of message objects is also very simple. You only need to implement the iMessage interface.
Public class register implements iMessage {public function register () {} public var Username: string; Public var Email: stringpublic function load (data: reader): void {username = data. readutf (); email = data. readutf ();} public function save (data: writer): void {data. writeutf (username); data. writeutf (email );}}
Sending this message is also relatively simple
VaR REG: Register = new register (); Reg. Username = txtusername. Text; Reg. Email = txtemail. Text; mpackage. Send (Reg, msocket );
In fact, it is quite convenient to use the as socket. Many basic methods are provided, and even bytearray provides these basic and considerate methods.