应用程序设计和开发--FlashCom Develop阅读笔记 (十七)

2006-03-09 00:46:08

这篇内容主要讲述在FCS应用程序开发过程的一些建议和技巧,包含有服务器兼容性方面的建议、相互依赖关系、多文件管理、带宽管理、双字节支持、卸载和重载应用程序和动态访问控制等~ 一、服务器兼容性方面的建议 使用小写方式命名你的目录和文件名 Macromedia 推荐你使用小写字母命名FlashCom开发项目中的目录和文件,以便更好的工作在不同的服务器之间。 使用相对路径或绝对路径连接服务器 在Fcs开发中NetConnect.connect命令可以使用绝对和相对路径来连接指定的应用程序,如果你的swf文件和FlashCom服务器运行在同一台机器,你可以使用相对路径rtmp:/appName/instanceName 来代替 rtmp://server.domain.com/appName/instanceName 如果你的开发你的应用程序在一台开发服务器,并且没有使用相对路径在swf文件中,那么移动你的swf文件到产品服务器会带来一些额外的工作,因为你不得不更改每一个NetConnect.connect语句中url参数。 如果你的swf文件不会和flashCom服务器在同一台机器,那么必须加上绝对路径,(作者注:当然可以通过变量的方法来设置) 二、相互依赖关系 因为客户端和服务器端的ActionScript脚本代码都是应用程序的一部分,他们必须协调工作,并且相互依赖。一个最典型的例子就是在客户端和服务器端之间使用call命令,因为调用的方法可能是客户端或者服务器端自定义的。下面有个例子可以说明: 01 : // 客户端fla文件的 ActionScript 代码 02 : my_nc = new NetConnection(); 03 : my_nc.someClientMethod = function() 04 : { 05 : //在这里 添加你的处理代码 06 : } 07 : my_nc.connect(“rtmp://hostname:port/appname”); 08 : 09 : // 服务器端的main.asc中的 ActionScript 代码 10 : clientObj.call('someClientMethod'); 在服务器端clientObj.call方法传递的参数必须是在客户端已经定义好的NetConnect对象方法,这是因为任何客户端的需要被服务器调用的方法必须通过NetConnect对象连接到服务器才可以。 相反,你在客户端调用服务器端的方法 01 : // 客户端代码 02 : NetConnection.call( 'someServerMethod' ); 03 : 04 : // 服务器端代码 05 : client.prototype.someServerMethod = function() 06 : { 07 : // 这里是处理代码 08 : } 09 : // 或者使用下面的调用方式也是有效的 10 : onConnect(newClient) 11 : { 12 : newClient.someServerMethod = function() 13 : { 14 : // code 15 : } 16 : } 在这种情况下,NetConnect.connect方法的参数必须是服务器端(一般是main.asc)已经定义好的方法,这是因为任何服务器端需要被客户端调用的方法必须是服务器端的Client对象的方法。 三、使用多文件管理 当你的应用程序日益复杂的时候,不要企图通过一个单一的脚本来完成所有的事情。把你的函数分成不同的文件,每个提供一定的功能集合。如果你使用多个文件,还可以使用包含的方式来优化性能,使得同一段代码不需要被执行多次。 客户端 例如,在客户端,如果你想把my_file.as文件能够被应用程序中的其它文件调用,只需要在my_file.as文件开头写上下面的代码: 1 : if (_root._my_file_as == null) { 2 : _root._my_file_as = true; 3 : // All the code for myfile.as goes here 4 : } 然后,在其它文件中,包含下面代码: #include 'my_file.as'; 注意:include指令在编译时候被执行,而不是运行的时候执行。 服务器端 服务器端的方式有些区别,因为在服务器端的ActionScript不支持全局对象。例如,你要包含一个my_flie.asc文件,在该文件开头依然包含下面这段代码: 1 : if (_my_file_asc == null) { 2 : _my_file_asc = true; 3 : // All the code for myfile.asc goes here 4 : } 区别就在于其它文件包含该文件的时候不使用#include指令,而是使用load指令 load('my_file.asc'); 四、使用唯一的实体命名 通常的开发环境是多个用户同时连接到同一台服务器,为了避免数据流冲突或共享对象被覆盖,可以在NetConnect.connect命令中使用唯一的实体名称。 如果你想要使用NetConnect 调试工具,你必须在客户端代码的第一行包含NetDebug.as文件,(FlashCom1.5版本并没有包含NetDebug.as文件,你可以在这里下载)NetDebug.as文件的使用方法不在本文的说明范畴,留待以后再表。 五、强制显示Flash设置面板 当一个应用程序企图访问用户的摄像机或者麦克风,以及要在本地存储数据的时候,flash 会显示设置对话框来得到允许。用户也可以点击鼠标右键来打开设置面板。如果要强制显示设置面板,可以使用下面的代码: // 不带参数表示打开用户上次浏览的设置面板 1 : System.ShowSettings(); 2 : // 打开保密性设置面板 3 : System.ShowSettings(0); 4 : // 打开本地存储设置面板 5 : System.ShowSettings(1); 6 : // 打开麦克风设置面板 7 : System.ShowSettings(2); 8 : // 打开照相机设置面板 9 : System.ShowSettings(3); 例如,如果你的应用程序需要使用摄像头,你可能需要提示用户在弹出的保密性设置面板中选择允许。就必须使用 System.showSettings(0) 六、带宽管理 你可以通过计算近似的带宽承受度来控制服务器发送到每个客户端的数据量。有很多种方法可以做到,一种方法是配置FlashCom server的config.xml文件;另一种方法是使用NetStream.receiveVideo 方法来指定传输速率;第三种方法是通过设置客户端Camera.Quality属性和服务器端的Client.setBandwidthLimit方法。下面会详细讲述第三种方法。 Fcs自带的doc_bandwidth示例程序演示如何让用户选择不同的带宽设置。选择不同的带宽设置后,客户端的麦克风和摄像头设置也会根据用户的选择更新,服务器端的带宽限制也会更新。 客户端的ActionScript提供了一个用户界面让用户选择三种不同的带宽设置:Modem、DSL和LAN。当用户改变了带宽限制后,摄像头和麦克风设置也会更新,还有一个不引人注意的地方,就是up&#100;ateBandwidth方法也会根据设置的选择改变屏幕的尺寸。 01 : _root.Modem_btn.onPress = function() { 02 : // Call up&#100;ateBandwidth to change 03 : // camera and mic settings and inform 04 : // the server 05 : _root.up&#100;ateBandwidth(1); 06 : } 07 : _root.DSL_btn.onPress = function() { 08 : _root.up&#100;ateBandwidth(2); 09 : } 10 : _root.LAN_btn.onPress = function() { 11 : _root.up&#100;ateBandwidth(3); 12 : } 在fla文件的第一帧,你可以找到下面一段代码,用来初始化摄像头和麦克风,以及从服务器播放串流和根据用户的选择更新摄像头、麦克风的设置。 01 : #include 'NetDebug.as' 02 : stop(); 03 : // Initialize movie by getting a camera and microphone, and 04 : // Configure the initial camera and microphone settings 05 : client_cam = Camera.get(); 06 : client_cam.setMode(150,120,5); 07 : client_cam.setQuality(0, 90); 08 : client_mic = Microphone.get(); 09 : client_mic.setRate(22); 10 : // Get the stream to publish and play 11 : function getPlayStream() { 12 : // Get new net connection 13 : client_nc = new NetConnection(); 14 : // Handle status message 15 : client_nc.onStatus = function(info) { 16 : trace( 'Level: ' + info.level + newline + 'Code: ' + info.code); 17 : } 18 : client_nc.connect('rtmp:/doc_bandwidth/room_01'); 19 : // Create a stream to which to publish 20 : out_ns = new NetStream(client_nc); 21 : out_ns.attachVideo(client_cam); 22 : out_ns.attachAudio(client_mic); 23 : out_ns.publish('myAV'); 24 : Chapter 5 70 25 : // Create a stream to receive the published data 26 : in_ns = new NetStream(client_nc); 27 : Output_mc.fromSrvr.attachVideo(in_ns); 28 : Output_mc.fromSrvr.attachAudio(in_ns); 29 : in_ns.play('myAV'); 30 : } 31 : // Called from the bandwidth buttons 32 : function up&#100;ateBandwidth(b) { 33 : // Respond to a change in the bandwidth 34 : // If 'Modem' was sel&#101;cted 35 : if ( b == 1 ) { 36 : client_cam.setMode(160,120,2); 37 : client_cam.setQuality(0, 75); 38 : client_cam.setKeyFrameInterval(3); 39 : client_mic.setRate(5); 40 : // For demonstration purposes, change size of screen 41 : Output_mc._height = 100; 42 : Output_mc._width = 150; 43 : // If 'DSL' was sel&#101;cted 44 : } else if ( b == 2 ) { 45 : client_cam.setMode(160,120,5); 46 : client_cam.setQuality(0, 85); 47 : cam.setKeyFrameInterval(5); 48 : client_mic.setRate(11); 49 : // For demonstration purposes, change size of screen 50 : Output_mc._height = 130; 51 : Output_mc._width = 175; 52 : // If 'LAN' was sel&#101;cted 53 : } else { 54 : client_cam = Camera.get(); 55 : client_cam.setMode(160,120,15); 56 : client_cam.setQuality(0, 90); 57 : client_cam.setKeyFrameInterval(10); 58 : client_mic.setRate(22); 59 : // For demonstration purposes, change size of screen 60 : Output_mc._height = 150; 61 : Output_mc._width = 200; 62 : } 63 : // Call the server function setBandwidth and pass the user’s 64 : // sel&#101;ction, b. 65 : client_nc.call('setBandwidth', 0, b); 66 : } 67 : // Get the stream to play 68 : getPlayStream(); 在服务端的main.asc文件中,包含了setBandwidth方法,被客户端调用。 01 : // If server-side code is part of the application, 02 : // it must define an onConnect function that accepts 03 : // the client connection. 04 : application.onConnect = function(client) { 05 : // Establish the connection 06 : application.acceptConnection(client); 07 : } 08 : // Called when user presses a bandwidth choice (Modem=1, DSL=2, LAN=3) 09 : Client.prototype.setBandwidth = function(bw) { 10 : // set the bandwidth for the client 11 : if ( bw == 1 ) { 12 : // modem settings 13 : this.setBandwidthLimit( 35000/8, 22000/8 ); 14 : } else if ( bw == 2 ) { 15 : // DSL settings 16 : this.setBandwidthLimit( 800000/8, 100000/8 ); 17 : } else { 18 : // LAN settings 19 : this.setBandwidthLimit( 400000, 400000 ); 20 : } 21 : } 七、开发双字节应用程序 如果需要在服务器端的开发环境使用双字节文字,你的服务器端ActionScript代码必须使用utf-8编码。这意味着你必须采用支持UTF-8的编辑器书写代码,然后可以用内建的JavaScript方法,例如Date.toLocalString 来转换成本地编码。 如果使用双字节字符作为方法名称,必须使用对象数组操作方式而不能用点操作方式。 1 : // 使用双字节命名的方法格式 2 : obj['方法名称'] = function(){ } 3 : // 使用单字节命名的方法格式 4 : obj.MethodName = function() { } 八、卸载和重载应用程序 应用程序实体会自动卸载通过垃圾回收机制。当所有的用户断开应用程序的连接的时候,垃圾回收会首先运行,然后应用程序会自动卸载。换句话说,并不是所有用户断开连接的时候应用程序就马上卸载。因为应用程序的启动通常需要一段时间,所以下一个客户端的连接并不会占用启动的开销。 默认,垃圾回收每20分钟发生一次,你可以修改这个值(必须大于0)。 当你对main.asc文件有任何修改的时候,你必须重载应用程序才可以生效。而这样就会断开当前所有用户的连接。重载应用程序的方法可以通过管理控制台和应用程序监视器来完成。 九、执行动态访问控制 服务器端的ActionScript给共享对象和串流对象提供了执行动态访问控制列表(ACL)的功能机制。默认所有的连接对串流和共享对象有完全访问权限。你可以控制某个用户具有创建、读写共享对象和串流的权限,每个连接到服务器端的应用程序实体都会有一个服务器端的Client对象参考,并且每一个Client对象都有两个属性:readAccess和writeAccess。使用这两个属性,就可以设置每个连接的权限。 下面有个示例: client.readAccess = 'appSO/' client.writeAccess = 'appStreams/public/;appSO/public/' 该例子说明了对一个Client对象实体client作了权限控制 如果要对全部Client对象设置权限,可以使用 client.readAccess = 'appSO/' ; //所有客户端都可以访问appSO目录 client.writeAccess= 'appSO/public/'; //所有连接的客户端都可以该目录下创建共享对象或数据流 但是却无法写入 appSO/private/ 目录。 表情组件中的历史记录限制 使用表情组件以后,以前的历史记录限制的方法就不行了,需要修改表情组件来实现。 在parseString方法中找到: 1 : this.msgHistory_array.push({ _str:str, _beginIndex:beginIndex, _endIndex:endIndex }); 在下面增加代码: 1 : if (this.msgHistory_array.length>30) { 2 : this.msgHistory_array.shift(); 3 : this.smiley_mc_array.shift(); 4 : } 这样把历史记录数组限制到了一定数目,但是文本框内的显示仍然没有限制,因为文本框的显示是通过 1 : this.smiley_txt.htmlText += ' + this.smiley_fmt.font + '\' size=\'' + this.smiley_fmt.size + '\'>' + this.str.rightTrim() + ' '; 输出的. 我尝试修改输出方式如下: 在开始保存字串信息到数组 1 : tempstr=''; 2 : for (i=0;i < this.msgHistory_array.length;i++){ 3 : tempstr += this.msgHistory_array[ i ]['_str']; 4 : } 在输出的时候使用this.smiley_txt.htmlText = tempstr;