【flex、Red5】Red5服务器+flex客户端中xml数据的压缩以及传输

来源:互联网 发布:汕头网店美工培训 编辑:程序博客网 时间:2024/06/11 08:43

【情景】:

flex客户端通过共享对象,向连接到Red5服务器的其他客户端传输xml数据,运行环境为无线局域网+60个客户端(安卓平板)+一个Red5服务器。

【问题】:

当传输小xml数据的时候,利用共享对象m_mainSharedObject.send("ReceiveMessage", message);这种方式对所有客户端进行广播,网络压力以及客户端响应速度勉强达标,但是一旦xml数据过大(超过1M,可能达到20M左右),整个网络环境的压力变大,客户端在接收广播消息的时候,出现明显的前后延迟以及网络堵塞的情况。

【解决方案】:

由于Red5在将信息发送至客户端的时候,主要以String类型或者能够转换成为String类型的数据结构为主,所以尝试用其他数据结构传输变为不可能;

其次,由于xml数据异常臃肿,并且由于软件结构导致的不能更换xml这种结构的数据,所以采用了一种压缩xml的想法来解决这个问题,主要是将传输的压力降低。

【方案测试】:

1、由于是客户端为安卓的平板,所以使用了第三方jar包中的xml压缩算法进行压缩,用PC测试demo,压缩效果非常明显,但是相同的算法移植到平板之上之后,压缩过程的持续时间,那是相当的长,大约PC压缩只要2s左右的xml数据,平板要5分钟左右(真实数据统计),M大小的xml数据能压成KB大小(效果很好),算法为bzip2,第三方包为apache社区的通用包。有兴趣的可以试一下,我把工具代码(单纯的压缩代码,网上都有,各种各样,童叟无欺!)贴下来,使用方式也一样贴出来:

package com.Zhang;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.InputStream;import java.io.OutputStream;import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;import org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream;public class XMLTool {public static final int BUFFER = 1024;  public static final CharSequence EXT = ".bz2";  /** * 【功能】:XML压缩工具类 * @author zhanghc 2015-07-23 */public XMLTool() {// TODO 自动生成的构造函数存根System.out.println("XML 工具类开始进行实例化");}    /**      * 数据压缩      *       * @param data      * @return      * @throws Exception      */      public static byte[] compress(byte[] data) throws Exception {          ByteArrayInputStream bais = new ByteArrayInputStream(data);          ByteArrayOutputStream baos = new ByteArrayOutputStream();            // 压缩          compress(bais, baos);            byte[] output = baos.toByteArray();            baos.flush();          baos.close();            bais.close();            return output;      }        /**      * 文件压缩      *       * @param file      * @throws Exception      */      public static void compress(File file) throws Exception {          compress(file, true);      }        /**      * 文件压缩      *       * @param file      * @param delete      *            是否删除原始文件      * @throws Exception      */      public static void compress(File file, boolean delete) throws Exception {          FileInputStream fis = new FileInputStream(file);          FileOutputStream fos = new FileOutputStream(file.getPath() + EXT);            compress(fis, fos);            fis.close();          fos.flush();          fos.close();            if (delete) {              file.delete();          }      }        /**      * 数据压缩      *       * @param is      * @param os      * @throws Exception      */      public static void compress(InputStream is, OutputStream os)              throws Exception {            BZip2CompressorOutputStream gos = new BZip2CompressorOutputStream(os);            int count;          byte data[] = new byte[BUFFER];          while ((count = is.read(data, 0, BUFFER)) != -1) {              gos.write(data, 0, count);          }            gos.finish();            gos.flush();          gos.close();      }        /**      * 文件压缩      *       * @param path      * @throws Exception      */      public static void compress(String path) throws Exception {          compress(path, true);      }        /**      * 文件压缩      *       * @param path      * @param delete      *            是否删除原始文件      * @throws Exception      */      public static void compress(String path, boolean delete) throws Exception {          File file = new File(path);          compress(file, delete);      }        /**      * 数据解压缩      *       * @param data      * @return      * @throws Exception      */      public static byte[] decompress(byte[] data) throws Exception {          ByteArrayInputStream bais = new ByteArrayInputStream(data);          ByteArrayOutputStream baos = new ByteArrayOutputStream();            // 解压缩            decompress(bais, baos);            data = baos.toByteArray();            baos.flush();          baos.close();            bais.close();            return data;      }        /**      * 文件解压缩      *       * @param file      * @throws Exception      */      public static void decompress(File file) throws Exception {          decompress(file, true);      }        /**      * 文件解压缩      *       * @param file      * @param delete      *            是否删除原始文件      * @throws Exception      */      public static void decompress(File file, boolean delete) throws Exception {          FileInputStream fis = new FileInputStream(file);          FileOutputStream fos = new FileOutputStream(file.getPath().replace(EXT,                  ""));          decompress(fis, fos);          fis.close();          fos.flush();          fos.close();            if (delete) {              file.delete();          }      }        /**      * 数据解压缩      *       * @param is      * @param os      * @throws Exception      */      public static void decompress(InputStream is, OutputStream os)              throws Exception {            BZip2CompressorInputStream gis = new BZip2CompressorInputStream(is);            int count;          byte data[] = new byte[BUFFER];          while ((count = gis.read(data, 0, BUFFER)) != -1) {              os.write(data, 0, count);          }            gis.close();      }        /**      * 文件解压缩      *       * @param path      * @throws Exception      */      public static void decompress(String path) throws Exception {          decompress(path, true);      }         /**      * 文件解压缩      *       * @param path      * @param delete      *            是否删除原始文件      * @throws Exception      */      public static void decompress(String path, boolean delete) throws Exception {          File file = new File(path);          decompress(file, delete);      } }


    private void testDataCompress() throws Exception {            byte[] input = inputStr.getBytes();          System.err.println("原文长度:\t" + input.length);            byte[] data = DsXMLTool.compress(input);          System.err.println("压缩后长度:\t" + data.length);           byte[] output = DsXMLTool.decompress(data);          String outputStr = new String(output);          System.err.println("解压缩后:\t" + outputStr);          System.err.println("长度:\t" + output.length);        }  

2、利用flex里面的ByteArray进行数据压缩,然后将数据传输到Red5服务器上,其余客户端从Red5服务器上获取压缩打包后的xml数据,下载到本地进行解压缩,并执行相应的xml命令。

在探索解决方案的时候,遇到过几个问题,最开始,我是想直接用共享对象的广播将压缩后的数据发送出去,但是Red5只能够传输内容可以强转为String字符串型的数据,其余的数据是不会传输的,比如我传输一个Array,Array里面放着Object,Object中包含着各种属性,其中有一个属性是Object,然后这个属性Object的一个属性是String,但是不论这个String的长度大小是多大,广播数据都不会把这些数据发送出去的,只会发送Object这个实例的一般属性,内容中我们想要的却没有。

因此,我想到一种解决方案,就是像现在这样,用flex本身的数据结构,将数据压缩,然后将压缩后的数据保存在服务器上,其余客户端通过http方式进行数据的下载,以及本地的还原,局域网的http数据传输经过测试,10M左右的数据,60个客户端都可以完整收取数据内容,并发量以及稳定性客观。

首先,将要压缩的xml数据变为String,然后压缩:

var data:ByteArray = new ByteArray();data.writeUTFBytes(str);data.compress();
然后,将压缩后的数据保存在服务器上(自己拼表单):

public function upLoadActionXML(data:ByteArray):void{data.position = 0;var _XMLName:String = "想要的姓名" + ".txt";//文件名(可以随意命名,后缀可以是.xml,自己喜好)m_XMLPath = m_strSaveRootPath + _XMLName;//文件保存路径(自定义)var form:MsMultiPartFormData = new MsMultiPartFormData(); form.AddFormField("devilField", "devilField"); form.AddStreamFile("fileUpload", _XMLName, data);form.PrepareFormData(); var request:URLRequest = new URLRequest(m_strServerRootPath); var header:URLRequestHeader = new URLRequestHeader("Content-Type", "multipart/form-data; boundary=" + form.Boundary); request.requestHeaders.push(header); request.method="POST";        request.data = form.GetFormData();      var m_URLLoaderRealFile:URLLoader = new URLLoader(request);m_URLLoaderRealFile.addEventListener(Event.COMPLETE, onUpLoadComplete);//监听上传成功运行的函数}

拼接表单的自定义类:

package OnLineCourse.UpLoad{import flash.utils.ByteArray;/**  * 用于打包multipart/form-data格式HTTP数据包的类  */ public class MsMultiPartFormData  { public var Boundary:String= "---------------------------zhanghcgdagjv56347"; private var fieldName:String="Content-Disposition: form-data; name=\"XXXX\""; private var fieldValue:String= "XXXX"; private var fileField:String="Content-Disposition: form-data; name=\"XXXX\"; filename=\"XXXXXXXX\""; private var fileContentType:String= "Content-Type: XXXX"; private var formData:ByteArray;  /**  * ...  * @author qwliang  */ public function MsMultiPartFormData () { formData=new ByteArray(); } public function AddFormField( FieldName:String,  FieldValue:String):void { var newFieldName:String=fieldName; var newFieldValue:String=fieldValue; newFieldName=newFieldName.replace("XXXX",FieldName); newFieldValue=newFieldValue.replace("XXXX",FieldValue); formData.writeMultiByte( "--"+Boundary+"\r\n","UTF-8"); formData.writeMultiByte( newFieldName+"\r\n\r\n","UTF-8"); formData.writeMultiByte( newFieldValue+"\r\n","UTF-8"); } public function AddFile( FieldName:String, FileName:String,FileContent:ByteArray, ContentType:String):void { var newFileField:String=fileField; var newFileContentType:String=fileContentType; newFileField=newFileField.replace("XXXX",FieldName); newFileField=newFileField.replace("XXXXXXXX",FileName); newFileContentType=newFileContentType.replace("XXXX",ContentType); formData.writeMultiByte( "--"+Boundary+"\r\n","UTF-8"); formData.writeMultiByte( newFileField+"\r\n","UTF-8"); formData.writeMultiByte( newFileContentType+"\r\n\r\n","UTF-8"); formData.writeBytes(FileContent,0,FileContent.length); formData.writeMultiByte("\r\n","UTF-8"); } public function AddStreamFile( FieldName:String, FileName:String,FileContent:ByteArray):void { AddFile( FieldName, FileName, FileContent,"application/octet-stream"); } public function PrepareFormData():void { formData.writeMultiByte( "--"+Boundary+"--","UTF-8"); } public function GetFormData():ByteArray { return formData; } } }

从服务器上下载数据就很简单了:

var urlLoader:URLLoader = new URLLoader();urlLoader.dataFormat = URLLoaderDataFormat.BINARY;urlLoader.addEventListener(Event.COMPLETE, onGetBINARY);urlLoader.addEventListener(IOErrorEvent.IO_ERROR, onGetError);urlLoader.load(new URLRequest(path));
然后获取到数据之后,进行解压缩处理:

private function onGetBINARY(event:Event):void {var xmlData:XML = new XML();if (event.type == Event.COMPLETE){var data:* = URLLoader(event.target).data;if (data is ByteArray){try{ByteArray(data).uncompress();}catch(e:Error){}}xmlData = XML(data);}}
这样就完成了整个大体积xml数据的压缩-传输-下载-还原的流程。




1 0
原创粉丝点击