【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数据的压缩-传输-下载-还原的流程。
- 【flex、Red5】Red5服务器+flex客户端中xml数据的压缩以及传输
- Flex客户端设置speex编码时Red5对音频数据的处理以及将speex解码
- Flex+Red5学习笔记(3)------调用red5服务器
- Flex客户端与Red5通信示例
- Flex客户端与Red5通信示例
- red5+flex应用开发
- flex + red5实现视频会议
- Flex 连接 red5
- flex+red5视频播放器
- Flex+Red5实现在线视频播放
- red5与flex通信 HashMap
- red5流媒体服务器的安装与配置(FLEX与JAVA的结合)
- 使用 Flex 和Java servlets 将文件上传到 RED5 服务器的步骤
- Java与Flex学习笔记(16)---Red5流媒体服务器的安装与测试
- 使用 Flex 和Java servlets 将文件上传到 RED5 服务器的步骤
- Flex+Red5学习笔记(2)-----修改Red5服务
- Flex+ Red5 学习笔记(1)-----red5部署至tomcat
- 玩转Red5+Flex(1)——Red5介绍
- Android 之LayoutInflater详解
- HDU 5355 Cake (WA后AC代码,详细解析,构造题)
- yarn架构-Capacity Scheduler
- codeforces 558C
- 老菜鸟致青春,程序员应该选择java 还是 c#
- 【flex、Red5】Red5服务器+flex客户端中xml数据的压缩以及传输
- android animation的简单使用
- 浏览器向服务器发送请求报文
- 手机开发之H5+规范的原生UI警示框
- 【黑马程序员】Java笔记--集合框架
- 各种创建单例模式的优缺点
- Backbone.js快速入门(一)
- 【leetcode】 Largest Rectangle in Histogram
- Swift学习笔记之基本运算符(一)