关于Flash Media Server

Posted on 2006-09-20 16:35  Zcr  阅读(8009)  评论(1编辑  收藏  举报

原 Flash Communication Server 已经正式改名为 Flash Media Server.

Flash Media Server 2.0 的最新消息
http://macromedia.breezecentral.com/p37828859/

1,运行多个应用程序和主机更加稳定
2,支持更多用户连接
3,数据缓存功能
4,更好的集群和负载均衡
5,增强高质量大文件视频回放
6,改进的管理和监视工具
7,服务器将记录更多更详细的log信息
8,XML接口的服务器管理和监视
9,用户自定义的访问控制
10,自动检测播放器.
11.数据支持加密传输
12,增强的API:
-服务器端支持XML sockets
-服务器端支持Web Services
-服务器端支持JPG流
-服务器端支持文件系统访问(有安全沙盒限制) 

Macromedia公司发布Macromedia Flash Media Server 2,这款服务器软件成功组合了传统流媒体功能和灵活的开发环境,用于创建和交付创新的互动式媒体应用。作为最近发布的Macromedia Flash Professional 8和Flash Player 8的补充,Flash Media Server 2使Flash Platform成为用于跨各种浏览器和操作系统创建、提供互动式富媒体应用的领先的解决方案。目前,领先的媒体、娱乐、电信、零售和广告等行业用户迅速采用Macromedia Flash Video,用于为全世界数百万浏览者提供定制的、无缝的视频体验。

  Flash Platform提供了一流的网络视频体验。如今,绝大部分的网络视频需要利用一大批眼花缭乱的可选件和下载件才能展示,如果把最新发布的Flash Media Server 2与无所不在的Flash Player相结合,就能跨众多平台、各种连接速率和浏览器,可靠地提供流畅、即时的视频体验。发布者也可以把视频集成到自己的网站和应用当中,而且可以完全控制回放、互动和品牌建立,获得无缝体验。

  Macromedia高级副总裁、总经理Tom Hale说:“Flash Platform是向互联网上最广泛的受众提供网络视频和丰富媒体应用的最佳方式,就集成到网络体验当中的流视频而言,目前还没有比Flash Media Server 2更好的选择。”

  Flash Media Server 2是在大规模部署环境下提供录制和实况Flash Video的基础,如视频点播、实况网络广播、MP3媒体流、视频博客和视频/音频聊天等应用。新版本引入了可扩展的新款Edge-Origin服务器,这个企业级就绪的可选架构简化了负载均衡、故障替换和集群工作,从而能够确保流式传输富交互体验具有更高的可靠性和扩展性,即使是在流量高峰期间。Flash Media Server 2拥有独特的可编程流媒体环境,包括性能可靠的应用编程接口(API),对媒体流、资产和特性(如定制互动、用户验证和带宽检测)实现精确的代码控制,从而提供真正不同的用户体验。Flash Media Server 2视频体验充分利用了Flash Player 8中新的高质量视频编解码器,并具有自动检测客户端的带宽连接、相应调整媒体流的功能。

  Scripps Networks公司的Flash开发人员Tim O'Hare说:“在HGTVPro,我们的主要挑战是,开发出生动而丰富的宽带视频应用,来满足最终用户和广告客户不断提高的要求。通过使用Macromedia Flash Media Server 2和Macromedia Flash Professional,我们获得了前所未有的能力,来创建并向我们的广大受众展示了HGTVPro一系列的互动内容。现在,Flash Media Server 2提供了Flash Video流式传输方面的增强功能新选项,让我们可以部署更广泛的内容,更重要的是,这些内容可以通过多种平台来浏览。凭借极具互动性、创新性的控制功能,Flash Video提供了其他任何媒体播放器根本不可能提供的网上内容。”

  Flash Media Server可以在标准的Windows或Linux服务器上运行,可以与现有的数据库、万维网和数据服务集成。进一步拓展的扩展功能使用户能够管理基于XML的媒体元数据、访问本地系统资源、控制日志和报告,以便与现有的媒体吸收和管理系统更紧密地进行集成。

原 Flash Communication Server 正式改名为 Flash Media Server

FMS2 还是不给屏幕共享功能,我们可以通过第三方软件实现的.

VH Screen Capture Driver

Camtasia Studio

The scalable media server for streaming interactive media applications

Macromedia Flash Media Server 2 software offers the unique combination of traditional streaming media capabilities and a flexible development environment for creating and delivering innovative, interactive media applications to the broadest possible audience.

发布地址:http://www.macromedia.com/software/flashmediaserver/

免费开发版下载http://www.macromedia.com/cfusion/tdrc/index.cfm?product=flashmediaserver

FMS2组件更新

免费开发版下载

 

FLASH COM学习笔记1

第一章

内容:本人学习FlashCom Develop的阅读笔记,陆续提供,仅供参考,不作它用
心得作者:Liu21st

第一章  开始
一、FlashCom开发所需安装的软件和硬件:
1. FlashMX authoring
2. FlashMX Communication Server
3. ActionScript editor (笔者推荐 editplus )
4. Flash Player
5. Camera and Micophone

二、设置开发环境
1. 确保FlashCom server已经启动
2. 更改运行FlashCom Server的URL地址
    new_nc.connect('rtmp:/video/room_01');//本地服务器
    或者使用
    new_nc.connect('rtmp://www.liu21st.com/video/room_01');//远程服务器
  如果使用simpleconnect组件,直接在组件的属性中设置即可
3. 指定发布格式
   一般为html和swf
4. 书写client-side 的as脚本,一般写在第一帧
5. 书写server-side的asc脚本,一般为main.asc或组件对应的app_name.asc
6. 加载组件,如果使用默认的组件,可以通过下面的语句简单加载
   load('components.asc');//该文件在scriptlib目录下面
7. 初始化 client-side 代码. 给第一行添加下面代码
     #i nclude 'Netdebug.as'
     以便进行NetConnection 调试(ps.新版的FlashCom Server已经不包含netdebug.as文件,需要安装Flash Remote )
8. 监视应用程序
  通过FlashCom自带的应用程序管理器和管理工具来监控和管理 [ 中文版见这里 ]
 
三、大致开发步骤
 1. 设定应用程序目录并在服务器端注册
   在服务器端的application目录下建立相应的子目录就可以了(也就是项目main.asc文件所放置的目录了)记住服务器端的任何改动都需要重启FlashCom Server才能生效
 2.  在客户端建立链接

  1.     my_nc = new NetConnection();
  2.       my_nc.connect('rtmp://www.liu21st.com/app_name');//app_name即为新建的子目录名


 3. 保存客户端的fla文件到任何地方(如果涉及后台交互的话建议保存在webserver目录下)
 4. 如果包含client端需要相应的server端的asc文件,请拷贝到server端的相应目录(建议保持和客户端相同的文件名,而只是后缀不同)
 5. 然后发布你的swf文件并运行
 
默认的服务器端asc文件存储位置在C:\Program files\Macromedia\Flash
Communication Server MX\applications in Windows or /opt/macromedia/flashcom/applications
on UNIX.当你需要创建一个communciation应用程序时,就需要在applications下面建立子目录,存放下面的数据文件:
  asc 服务器端通信文件
  flv  数据流播放文件
  fso 远程共享对象数据文件
客户端的swf和html(或者php等服务器文件)可以放在你指定的任何目录,在产品发布的时候需要移走fla源文件。
每一个应用程序的实例也位于不同的目录,如:

my_nc.connect('rtmp://www.liu21st.com/chatApp/room_01')
my_nc.connect('rtmp://www.liu21st.com/chatApp/room_02')


如果没有指定实例,客户端实际上连接到一个默认的名为_defInst_的实例,可以对不同的实例建立不同的共享对象

01 : // One instance of application 'support'
02 : first_nc = new NetConnection();
03 : first_nc.connect('myserver.mydomain.com/support/session1');
04 : first_so = SharedObject.getRemote('CustomerInfo', first_nc.URI, false);
05 : first_so.connect(first_nc.URI);
06 :
07 : // Another instance of application 'support'
08 : second_nc = new NetConnection();
09 : second_nc.connect('myserver.mydomain.com/support/session2');
10 : second_so = SharedObject.getRemote('CustomerInfo', second_nc.URI, false);
11 : second_so.connect(second_nc.URI);



四、在FlashCom中使用的文件类型
 1. ASC 和 JS 文件 服务端使用的文件类型
   Flash Communication Server 在 服务端的scriptlib 目录下提供了一个脚本库,包含了一些组件和Flash Remoting services.的server端脚本
 2. FLV 和 IDX 文件 视频播放文件和索引文件
 3. SOL, SOR 和 FSO文件 共享对象数据文件(依次为Local、Remote和两者)

FLASH COM学习笔记:2 连接示例

一个简单的连接服务器示例
首先确保服务器已经启动,在windows下面可以直接启动服务就可以了。在Linux下面需要运行 server start命令启动。
在客户端写代码打开连接
my_nc = new NetConnection();//创建连接对象
my_nc.connect(targetURI);//连接服务器
参数格式为:其中实例名可以省略
rtmp://localhost:port/appName/instanceName //本地服务器
也可以省略前面的直接写成
rtmp:/appName/instanceName
rtmp://host:port/appName/instanceName//远程服务器
注意协议类型一定要使用rtmp,否则会连接失败
下面是一个简单的实现方法:

1 : //获取和设置摄像头
2 : client_cam = Camera.get();
3 : Live_video.attachVideo(client_cam);



//建立远程连接

1 : function doConnect() {
2 : client_nc = new netConnection();
3 : client_nc.onStatus = function(info) {
4 : trace('Level: ' + info.level + ' Code: ' + info.code);
5 : }
6 : client_nc.connect('rtmp://localhost/doc_connect/room_01');
7 : }



//发布视频流

1 : function publishMe() {
2 : out_ns = new netStream(_root.client_nc);
3 : out_ns.attachVideo(client_cam);
4 : out_ns.publish('myTestStream');//采用默认的live播放形式
5 : }



//播放视频流

1 : function playMe() {
2 : in_ns = new netStream(_root.client_nc);
3 : Published_video.attachVideo(in_ns);
4 : in_ns.play('myTestStream');
5 : }



定义好这些函数后,就可以用下面的代码简单实现

1 : // Connect to the server
2 : doConnect();
3 : // Publish the live stream
4 : publishMe();
5 : // Play back the stream from the server
6 : playMe();
 
FLASHCOM 学习笔记:3 数据流
 
第二章 Flash Communication Server结构概要
Flash Communciation Server 包含了server端(由一些asc文件组成)和client端(swf文件)
server端和client端的数据传输通过Real-Time Message Protocol (RTMP)进行实时交流,web server通过http服务把内容提供给client端,实现模式如下图:
450) {this.resized=true; this.width=450;}" border=0>
多用户可以连接到同一个应用程序Application
450) {this.resized=true; this.width=450;}" border=0 resized="true">
Flash Communciation Server实际上为不同的用户之间提供了相互交流的通道。

基于客户/服务器模式的application,服务器端主要负责数据的传输,由客户端发送请求,服务器端执行数据查询和计算并返回结果值给客户端,通常需要保持长时间的连接。

Flash Communciation Server提供了两种方法控制用户的更多交互:数据流和共享对象.
数据流是指在服务器端和客户端同步传递的音频、视频和其它数据的信息流,数据流可以通过简单的发布和订阅方式实现。一个发布的数据流可以实时的被看到(如视频聊天室),
450) {this.resized=true; this.width=450;}" border=0>
也可以被录制下来以后播放。
450) {this.resized=true; this.width=450;}" border=0>
录制的数据流被存为Flash Video (FLV) 格式,其中可以包含文本、音频和视频等信息。当然你也可以把存在的通过第三方的软件录制的视频和音频文件转换为flv格式的文件。
 
FLASH COM学习笔记. 4:共享对象
 
共享对象
在FlashCom 开发过程种可以使用两种共享对象:本地和远程共享对象。
本地共享对象可以看作是Flash cookie,可以在用户的本地机器存放用户数据,其本身为Flash player提供,可以无须FlashCom Server的支持。
远程共享对象是由FlashCom Server来管理的,提供了信息和数据的同步,以及数据的存储。
Flash客户端连接、提交给远程共享对象,并且与服务器端保持同步。信息数据还可以发布到所有连接到远程共享对象的客户端,并通过应用程序的session或临时文件持续。更多的信息请参考共享对象类。
450) {this.resized=true; this.width=450;}" border=0 resized="true">

连接外部数据源
根据FlashCom的数据流和共享对象提供的交流模型,FlashCom Server还可以和外部数据源交互,例如web 服务器、关系数据库,甚至其它的FlashCom Server应用程序。例如,你可以写一个服务器端的脚本文件来连接一个web服务器或ColdFusion应用程序来接收一串用户名和电话号码的列表,然后把查询结果写入共享对象。详细的方法后面的章节会描述。
450) {this.resized=true; this.width=450;}" border=0 resized="true">

创建和开发应用程序的流程
你可以使用FlashMX创作工具来创建应用程序的客户端组件,生成的swf文件提供了应用程序的用户界面,其中也包含了与FlashCom Server连接和控制的as脚本。
服务器端则需要相关的应用程序目录,其中包含了运行客户端所需要的asc脚本,提供多个客户端之间逻辑控制和数据交换。
450) {this.resized=true; this.width=450;}" border=0 resized="true">
在开发应用程序的过程种,客户端程序需要发布到合适的位置以保证应用程序的正常运行,这通常要结合Web Server,如html、php、asp等,因为FlashCom Server采用rtmp协议,所以web server并非必须,你可以直接在swf文件中执行,但不推荐这样做。
服务器端程序(包含asc、flv等文件)需要放置到正确的应用程序目录下面。
450) {this.resized=true; this.width=450;}" border=0 resized="true">
如果你是一个FlashCom Server管理员,你可以使用管理控制台来配置FlashCom server、设置系统安全、监视使用情况,停止和重启server,还可以添加用户。这需要用来第一章提到的 应用程序管理器和管理工具
450) {this.resized=true; this.width=450;}" border=0 resized="true">
 
FLASH COM学习笔记.5.应用示例
 
/*
+-------------------------------------------------------------------
| FlashCom 阅读笔记
| 版本: 1.0
| 作者: Liu21st 晴天的鱼
| 邮箱: Liu21st2002@msn.com
+-------------------------------------------------------------------
| 版权声明: Copyright◎ 2004-2005 世纪流年 版权所有
| 个人笔记 未经允许,严禁转载
| 主页: http://blog.liu21st.com
+-------------------------------------------------------------------
*/

下面内容主要讲述如果用如何通过客户端连接服务器,怎样访问共享对象,以及调用远程方法等。
当用户使用客户端的swf文件连接服务器时,服务器会加载应用程序,如果没有运行就创建实例。服务器端接受连接之后,产生一个新的客户端对象回应该客户端应用程序,执行指定的服务器端脚本。客户端需要做的是初始化数据流和共享对象等
连接流程
当客户端开始连接服务器后,服务器端会调用onAppStart方法(确保应用程序实例已经处于运行状态)
接下来,服务器端会回调客户端定义的onConnect方法,该方法的逻辑决定了是否接受该连接请求。当客户端断开连接的时候,会调用服务器端的onDisconnect方法;当应用程序结束后,会调用onAppStop方法
450) {this.resized=true; this.width=450;}" border=0 resized="true">

远程方法调用
在连接成功之后,客户端可以调用服务器端组件定义的方法,服务器端也可以调用客户端组件中的方法。
每一个连接到服务器端的应用程序都作为一个服务器端的客户对象实例,每一个客户端的实例对象都可以通过NetConnect对象调用远程服务器的方法,然后服务器端可以回应并返回值给客户端。下面的图表示了在客户端调用服务器端方法并获取返回值的方法:
450) {this.resized=true; this.width=450;}" border=0 resized="true">

从服务器端回调客户端的方法
从服务器回调客户端的方法比较类似于上面所说的。在客户端,可以给NetConnect对象的实例自定义方法,在服务器端可以利用client.call的方式调用客户端的方法。图示即为从服务器调用客户端并返回值的方法。
450) {this.resized=true; this.width=450;}" border=0 resized="true">

共享对象的使用
共享对象简化了在多用户之间共享数据的开发工作,一个Flash 客户端要获取远程共享对象可以通过 SharedObject.getRemote来指定连接,
然后通过SharedObject.connect连接远程共享对象,一旦连接成功,服务器端会发送同步信息给各个连接的客户端,客户端使用SharedObject.onSync来保持同步,下面的图简单描述了其使用过程。
450) {this.resized=true; this.width=450;}" border=0 resized="true">
 
FLASH COM学习笔记.6.对象概述
 
/*
+-------------------------------------------------------------------
| FlashCom 阅读笔记
| 版本: 1.0
| 作者: Liu21st 晴天的鱼
| 邮箱: Liu21st2002@msn.com
+-------------------------------------------------------------------
| 版权声明: Copyright◎ 2004-2005 世纪流年 版权所有
| 个人笔记 未经允许,严禁转载
| 主页: http://blog.liu21st.com
+-------------------------------------------------------------------
*/

第三章 使用对象
Macromedia Flash Communication Server MX 1.5提供了两部分API,即客户端API和服务器端API。本章主要讲述客户端API和服务器端API是怎样使用的。也会涉及到共享对象的讨论,怎样存储关于应用程序和用户的相关信息。概述FlashMX Com Server的核心对象之后,我们也会重点描述一些类的细节内容,例如Camera, Microphone, NetStream, Stream, System和 Video 对象以及关于如何优化应用程序、保护客户端对象和使得NetConnection对象更安全。
客户端API提供了: Camera(摄影机), Microphone(麦克风), NetConnection(联机),NetStream(串流), SharedObject(共享对象)和 Video(视频). 服务器端API提供了下面这些对象: Application(应用程序), Client(客户端), NetConnection(联机), SharedObject(共享对象)和 Stream(串流).
客户端对象
下面的对象只能用于客户端的as脚本中
Camera 对象:允许你从摄影机捕捉视频并追加到任何一个MC中,当使用FlashMx Com server的时候,还可以在联机对象间传输、显示,甚至录制捕捉到的视频。应用这个特性,你可以开发例如视频会议、视频聊天等应用程序。
Microphone 对象 :该对象用于取得麦克风的声音来源,并且可以在联机对象之间传输、播放等,可以开发例如语音聊天之类的应用程序,如果不使用联机对象,也可以把声音通过音箱在本地输出。
NetConnection 对象:允许Flash客户端通过TCP socket与FlashCom Server建立连接,并且使用RTMP(Real-
Time Messaging Protocol,实时讯息通讯协议)交互数据。
NetStream 对象:在使用Netconnect对象所建立的联机对象上,进行数据、声音和视频信息的传输,就如同NetConnect的通道一样。
可以使用NetStream.publish方法来发步数据流,使用NetStream.play来播放接收到的数据流。
Localshared 对象:记录用户的资料,或者把讯息实时传递给所有联机用户。
Video 对象:用于显示通过NetStream.play方法或Camera.get方法捕捉到的视频流。并通过Video.attachVideo方法把该视频对象放置到flash的舞台。
服务器端对象
Application 对象:包含应用程序实体的信息与状态,直到程序结束为止。Application对象也可以让程序决定是否接收用户的联机或者关闭用户的联机,以及清除应用程序特定的流、清除在服务器端的共享对象,并让你在有效范围内访问整个应用程序的变量、定义相关事件所执行的函数等。
Client 对象:包含每个联机用户的信息,例如客户端的IP地址、Flash的版本信息、分配用户的频宽,或者呼叫客户端定义的方法等。
NetConnection 对象:可以在应用程序实体和服务器端,或者同一台服务器的另外一个应用程序之间创建一种双向的连接。你甚至可以使用服务器端的 NetConnection 对象来创建更强大的应用程序,例如你可以获取天气信息从另一个应用程序服务器或者和其他的Flashcom服务器及应用程序实体共享加载。使用联机对象,你可以使用标准的http协议或者rtmp协议在服务器之间交互和传递数据。
Remoteshared 对象:远程共享对象是在客户端建立的,但是可以在服务器端仍然可以使用,它可以实时地在客户端的多个应用程序之间共享和存储数据
SharedObject对象:作用和客户端建立的远程共享对象一样,让不同联机用户能够通过服务器端的共享对象实时分享信息。不过所提供的方法和客户端的有所区别。例如,读取服务器端的共享对象要用get方法,设定存储资料不用data属性,而使用setproperty和getProperty方法,另外还有暂时锁住和解锁的方法lock和unlock,防止资料会覆写。
Stream 对象:处理影音串流,传回录像文件的时间秒数、呼叫客户端串流对象中的自定义方法、以及播放与录像等方法。

客户端和服务器端的对象交流
某些对象的方法是可以在客户端或者服务器端建立和相互调用。例如当客户端的NetConnect对象联机到服务器端,服务器端的Netconnect对象同时也建立了,这个对象可以调用客户端NetConnect对象的副本的所有方法。下面的表格显示了对应的调用关系
     
  1. 客户端对象
     
  2. my_nc (NetConnection object)
     
  3. my_ns (NetStream object)
     
  4. my_so (remote shared object)
     
  5. 回应的服务器端对象
     
  6. my_client (Client object or application.clients object)
     
  7. my_server_stream (Stream object)
     
  8. my_server_so (server-side shared object)
     



下面表示了客户端的调用和服务器端的回应
     

  1.  
  2. 客户端的调用
     
  3. my_nc.connect 
     
  4. my_nc.close 
     
  5. my_nc.call('doThing'myCallbackFcn1'foo'
     
  6. my_so.send('doThing'1'foo')
     
  7. 服务器端的回应分别对应为
     
  8. application.onConnect
     
  9. application.onDisconnect
  10. my_client.doThing(1'foo')
  11. my_server_so.doThing(1'foo')



下面显示了服务器端的调用和客户端的回应
     

  1.  
  2. 服务器端的调用
     
  3. my_client.call ('doThing'myCallbackFcn,1'foo')
     
  4. my_server_stream.send ('doThing'1,'foo'
     
  5. my_server_so.send('doThing'1'foo'
     
  6. 客户端的回应分别对应为
     
  7.  my_nc.doThing (1'foo')
     
  8. my_ns.doThing (1'foo')
     
  9. my_so.doThing(1'foo')

FLASH COM学习笔记.7.理解共享对象

理解共享对象
共享对象可以存储任何Flash支持的数据类型。就存放位置来说,共享对象可以分成存在客户端计算机的本地型,以及存放在服务器上的远程型。你可以用它来记录用户的相关信息(如用户名、性别和其它设置参数等),或者用在服务器端,存储其它联机用户实时分享的信息(如聊天室的内容和线上用户名单等)
共享对象意味着用户可以在不同的用户之间、不同的同一台服务器上的应用程序实体。FlashCom server 支持三种不同的共享对象:Local、remote和server-side。下面简单介绍下这三个共享对象。

本地共享对象(Local shared object)
用于存取本地的数据,存储在用户的计算机硬盘中,并可以在不同的时间被其它应用程序访问。本地共享对象的扩展名为.sol,默认的存储路径是c:\documents and Settings\登录名称\Application Data\Macromedia\Flash Player\服务器网域名称\影片路径\影片文件名.swf\。本地共享对象也可以是短暂的,也就是说只有但应用程序运行时可用。我们也可以不连接Flashcom server而使用本地共享对象。更多的本地共享对象的信息,可以参考手册中的SharedObject.getLocal方法。
建立和存取本地共享对象的方法如下:

  1. var soSharedObject.getLocal('myCookie'//建立本地共享对象
  2. //存储资料
  3. //注意:不管是读取还是写入资料到本地共享对象,都必须通过data属性。
  4. so.data.userName='liu21st';
  5. so.data.msg='世纪流年';
  6. so.data.counter=10;
  7. //在默认状态下,以上资料并不会马上写入用户的磁盘,必须等到动画被关闭,或者用户离开你的网站后,才会写入磁盘。如果要立即写入的话,必须使用flush方法。如下:
  8. so.flush();



确认资料是否存储成功可以通过onstatus事件来获取
返回的code值为

SharedObject.Flush.Success(写入成功)
SharedObject.Flush.Failed(写入失败)
代码示例:

  1. so.onStatus = function (info){ 
  2. var status=info.code;
  3. if (status=='SharedObject.Flush.Success'){ 
  4.    trace('写入成功'); }
  5. else trace('写入失败');



远程共享对象(remote shared object)
通过Flash影片的ActionScript程序,在服务器端建立能让不同联机用户共同存取的资料,称为远程共享对象。和本地共享对象一样,远程共享对象可以被本地计算机存取,不同的是在资料存储在服务器端,所以任何用户都可以连接到远程共享对象访问到相同的信息。默认的存储路径是应用程序实体路径下的sharedobjects文件夹,扩展名是.fso。
远程共享对象也是最常用的共享对象类型。每当联机用户(或服务器端程序)更新远程共享对象的内容,其它联机到相同应用程序实体的用户将自动收到更新内容的事件(onSync),保持彼此资料的同步。聊天室应用程序就是运用这个机制建立的。
例如,你可以打开一个远程共享对象,如电话号码表(在服务器端持久有效)。当用户端对该共享对象作任何更改的时候,修改后的数据对其他连接到该远程共享对象的用户是自同步的。如果因为某种原因,更新了本地的数据信息但是没有连接到服务器,那么所作的更改会在下一次连接到服务器的时候同步远程共享对象。
更多的信息可以参考手册中的SharedObject.getRemote方法。

建立远程共享对象的方法:

  1. var client_nc = new NetConnection();
  2. client_nc.connect('rtmp://localhost/videochat/room1');
  3. so SharedObject.getRemote('records',client_nc.url);//数据资料不写入磁盘
  4. so.connect(client_nc);



远程共享对象的数据读取和写入方法和本地共享对象类似,也是通过data属性和flush方法。
使用下面语句可以把数据资料写入服务器端应用程序文件夹共享对象目录

  1. so SharedObject.getRemote('records',client_nc.url,true);
  2. //该语句远程共享的文件名将是records.fso



当远程共享对象的内容改变或者初次联机时,它都会向客户端发出onsync (同步)事件,好让所有联机用户都能实时取得最新的共享对象资料。
示例代码:

  1. so.onSync = function(list) { 
  2. for (var k in list) { 
  3. trace('name = ' + list[k].name ', event = ' + list[k].code);
  4.  }
  5. // do whatever else you want to do here
  6.  }



代理共享对象(proxied shared object)
代理共享对象是可以在用户端和服务器端共享的一种远程共享对象,区别在于它是由服务器端的ActionScript程序建立的,例如,在服务器端有两个聊天室的实体chat01和chat02,在chat02中可以连接到在chat01中定义的共享对象,更多的信息可以参考手册的SharedObject.get方法。
和客户端的sharedobject不同,设置共享变量的值要通过 SharedObject.setProperty,取得共享变量的值通过 SharedObject.getProperty 。
实例代码:

  1. application.appStart = function() { 
  2.      nc = new NetConnection();
  3.      nc.connect('rtmp://' master_server '/' master_instance);
  4.      proxySO SharedObject.get('myProxy',true,nc);   
  5.     // Now, whenever the client asks for a persistent 
  6.     // shared object called myProxy they will receive myProxy
  7.     // shared object from the master_server/master_instance
  8.  };



 

  1. myInfo SharedObject.get('foo');
  2. var addr myInfo.getProperty('address');
  3. myInfo.setProperty('city''San Francisco');
  4. var names sharedInfo.getPropertyNames();
  5. for (x in names){ 
  6.   var propVal sharedInfo.getProperty(names[x]);
  7.   trace('Value of property ' names[x] + ' = ' propVal); 
  8.  }



在使用远程共享对象之前,请确认SharedObject.connect 返回 true,在客户端调用SharedObject.flush 方法只是在本地拷贝了一份,要确保服务器端的拷贝,必须在服务器端使用SharedObject.flush 方法,如:

     
  1. // Sample server-side code for flushing a persistent shared object
     
  2. // to the server
     
  3. // Get the shared object when the application is loaded.
     
  4. application.onAppStart = function()
     

  5.  
  6. application.mySO SharedObject.get('SharedObjName'true);
     
  7.  }
     
  8. // When a user disconnects, flush the shared object.
     
  9. application.onDisconnect = function(client)

  10. application.mySO.flush();
  11.  }



如果在同一时间有多个客户端或者服务器端在同步远程共享对象的话,就会出现问题,要解决这个冲突可以通过下面的方法。
1. 使用不同的位置存储不同用户的信息
  这是最简单的一种方法,例如,在聊天室给每个用户不同的位置存放数据,同步只修改自己的数据部分。
2. 分配资料所有者
  复杂一点的方法就是定义一个用户为有限的时间内该数据资料的所有者,所有者可以锁定服务器端的共享对象,直到返回可用信息后方可同步另外的数据。下面是示例代码:
通过一个记录游戏最高分的应用程序来说明解决同步冲突的问题,当前系统保存的最高分是95,同时有两个用户打破了这个记录,成绩分别为105和110,如果不锁定最高分的话,两个成绩都会同时执行updateHighScore方法,有可能其中一个成绩会无法记录下来。使用锁定共享对象的方法解决了这样一个问题。

     
  1. application.onAppStart = function()
     

  2.  
  3. application.scoreSO SharedObject.get('high_score_so'true);
     
  4. application.scoreSO.onSync = function(listVal)
     

  5.  
  6. trace('got an onSync on scoreSO');
     
  7.  }
     
  8.  }
     
  9. application.onConnect = function(newClient,name,passwd)

  10. newClient.updateHighScore = function(final_score)

  11. application.scoreSO.lock();
  12. if (application.scoreSO.getProperty('high_score_so') < final_score)

  13. application.scoreSO.setProperty('high_score_so'final_score);
  14.  }
  15. application.scoreSO.unlock();
  16.  }
  17.  }



3. 通知客户端
 当服务器端收到客户端的同步请求的时候,SharedObject.onSync事件会通知用户端更改被拒绝,然后提供一个用户界面来给用户解决这种冲突。这种技术通常用于客户端不是经常更新的情况。
4. 接受某些,拒绝其它的
 应用程序根据“先到先服务”的原则来解决同步的冲突问题。通常需要于客户自己重新请求来解决冲突。
5. 通过send方法来提高控制级别
 SharedObject.send 命令给所有连接到该远程共享对象的客户端广播消息,也包括发送者本人。

FLASH COM学习笔记.8 Application对象

Application对象可以让你接受或拒绝用户端的连接请求,注册客户端相应事件的类和方法等。一般在服务器端的main.asc文件中定义相关事件。
服务器端的程序由下列事件程序组成:

1 : application.onAppStart = function(){
2 : //应用程序初次启动时,要执行的程序
3 : //并且只会被执行一次
4 : }



 

1 : application.onConnect = function(){
2 : //每当有用户链接到此应用程序时,要执行的程序
3 : //可以在这里读取用户端的数据
4 : //建立可以让客户端执行的方法
5 : //或者呼叫客户端的自定义方法等
6 : }


如果使用communication server组件的话,还可以使用Application.onConnectAccept 和 application.onConnectReject事件
可以查看下面的实例程序:

01 : // A user has connected
02 : application.onConnect = function( newClient, userName )
03 : {
04 : if (userName == 'admin')
05 : {
06 : newClient.adminFunc= function(param)
07 : {
08 : // some code that’s only useful to the admin
09 : newClient.myAdminProperty = param;
10 : }
11 : } else
12 : {
13 : // code for most cases
14 : }
15 : // Allow the logon
16 : application.acceptConnection( newClient );
17 : }
18 : // this part could be in a separate file
19 : // Every client (including admin) is going to have this function
20 : // (because of the way 'prototype' works).
21 : Client.prototype.commonFunction = function (myColor)
22 : {
23 : // some code
24 : // use this to refer to the client instead of newClient
25 : this.color = myColor;
26 : }


或者

01 : application.onConnect = function(clientObj,name,passwd)
02 : {
03 : // First accept the connection
04 : application.acceptConnection(clientObj);
05 : // After client is registered with the application instance
06 : // you can use 'call' method
07 : clientObj.call('onWelcome', 'You are now connected!!!');
08 : return;
09 : // Once you call acceptConnection or
10 : // rejectConnection within onConnect, return value is ignored.
11 : }


注意:如果要call客户端的方法,请确认已经调用application.acceptConnection以保证客户端正常连接。

1 : application.onDisConnect = function(){
2 : //当用户离线时,要执行的程序
3 : //可以在这里清楚用户的数据
4 : //和其它相关的程序
5 : }


可以参考下面的程序:

01 : // On the server side you would have the following
02 : application.onConnect = function(newClient, name)
03 : {
04 : newClient.name = name;
05 : return true;
06 : }
07 : application.onDisconnect = function(client)
08 : {
09 : for (var i = 0; i < application.clients.length; i++)
10 : {
11 : application.clients[ i ].call('userDisconnects'
, client,name);
12 : }
13 : }
14 : // On the client side you would have the following
15 : nc = new NetConnection();
16 : nc.userDisconnects= function (name) {
17 : trace(name + 'quits');
18 : }
19 : nc.connect ('rtmp:/app_name', userName);



 

1 : application.onAppStop = function(){
2 : //应用程序结束时,要执行的程序
3 : //也就是说所有的联机用户都离线后
4 : //这里的程序会被执行
5 : }



我们看到的main.asc文件可能并没有包含上面的任何一个事件,那是因为有可能通过load方法加载了其它的组件定义,但是我们仍然可以在main.asc文件中定义我们需要的事件和方法。

FLASH COM学习笔记.9 Camera对象

这一节主要讲述camera对象的使用,包括camera的使用优化、设置合适的带宽和如果使得一个camera用于多个应用程序。
Camera对象允许你从摄影机捕捉视频并追加到任何一个MC中,当使用FlashMx Com server的时候,还可以在联机对象间传输、显示,甚至录制捕捉到的视频。应用这个特性,你可以开发例如视频会议、视频聊天等应用程序。当然你也可以不通过服务器来使用Camera对象,例如可以捕捉你的视频并附加到某个MC。
Camera常用的属性:

     
  1. bandWidth 每秒种传送的最大字节数
     
  2. currentFps 当前传送的fps值
     
  3. fps setMode方法设定的fps值
     
  4. name 当前使用的摄像机名称
     
  5. names 可用视频捕捉设备的数组
     
  6. index 可以视频设备的索引值
     
  7. keyFrameInterval 关键帧间隔
     
  8. loopback 是否压缩影像
     
  9. motionLevel 灵敏度0~100 数值越高动作越迟钝
  10. width 影像的宽度
  11. height 影像的高度
  12. quality 传送的影像品质0~100
  13. muted 客户端是否允许Flash取用本地端的摄像机



需要创建Camera对象,使用下面代码:

1 : MyCamera = Camera.get();
2 : //如果有多个视频设备,请使用index(索引值)指定设备
3 : MyCamera = Camera.get(index);
4 :


如果在不同的网域访问,就会弹出窗口让用户确认使用或是拒绝使用:


当用户对弹出窗口响应后就会触发onStatus事件,请参考muted参数
当然也可以记住用户的选择,点击鼠标右键出现设置窗口


在该窗口选择允许,并选中记住,下次就不会弹出确认窗口了。
更高级的示例是弹出设备选择窗口让用户选择:

1 : camArray = Camera.names;
2 : if (camArray.length == 1){
3 : Camera.get();
4 : }
5 : else
6 : System.showSettings(3);//弹出视频设置窗口
7 : Camera.get();


 



Flashcomguru 的 arckid 提供了一个很好的检测Camera的方法,把它略作修改如下

01 : function checkforCam() {
02 : camArray = Camera.names;
03 : if (camArray.length >= 1){
04 : temp_cam = Camera.get();
05 : if(temp_cam == -1)
06 : trace('视频设备正忙');
07 : else
08 : trace('视频设备可用');
09 : delete temp_cam;
10 : } else if (camArray.length == 0) {
11 : trace('没有视频设备');
12 : }
13 : }
14 : //-----------------------------------------------------------------
15 : //或者下面的函数更精简:
16 : function checkForCam(){
17 : return Camera.names.length;
18 : }
19 : function isCamBusy(){
20 : if(arguments.length) return Camera.get(arguments[0]) == -1;
21 : return Camera.get() == -1;
22 : }
23 :



要设置Camera对象的模式,可以用setMode()方法,如下:

1 : MyCamera.setMode(width, height, fps [, favorSize])
2 : //width,height 是Camera对象宽高,默认值是160×120
3 : //fps 捕捉视频的速率 默认值是15
4 : //favorSize 是一个可选的布尔值,默认为true,表示采用最大匹配当前的窗口大小的速率,如果设为false,则会优先考虑影像的流畅度。


不同带宽的建议设置
默认的Camera设置对所有的带宽提供了一个相同的足够好的传输品质,如果需要手动设置以适应不同的带宽要求,设置Camera参数的方法如下:

  1. MyCamera.setQuality(bandwidthframeQuality)
  2. //bandwidth 频宽指每秒传送的最大字节数 默认为16384 如果设为0则维持frameQuality设定的影像品质,尽量使用最大频宽
  3. //freamQuality 影像的压缩品质1~100,设为0表示在bandwidth设定范围内自动调整影像品质


下面对不同的带宽给出了建议设置:

     
  1. Modem  ]
     
  2. 较低画质,较高动作流畅度 my_cam.setQuality(4000,0)
     
  3. 较高画质,较低动作流畅度 my_cam.setQuality(0,65)
     
  4. DSL ]
     
  5. 较低画质,较高动作流畅度 my_cam.setQuality(12000,0)
     
  6. 较高画质,较低动作流畅度 my_cam.setQuality(0,90)
     
  7. LAN ]
     
  8. 较低画质,较高动作流畅度 my_cam.setQuality(400000,0)
     
  9. 较高画质,较低动作流畅度 my_cam.setQuality(0,100)


打开和设置完Camera之后后要附加到一个视频实体才可以显示

  1. MyVideo.attachVideo(MyCamera);



正常关闭camera
如果你的应用程序使用camera对象和NetStream对象记录数据,camera仍然保持打开状态,为了确保关闭Camera对象,请在结束的时候使用

  1. NetStream.attachVideo(false)



在多个应用程序中使用同一个Camera
多个应用程序(swfs)可以在同时使用一个Camera。一般而言,多个浏览器窗口使用相同的进程,所以在浏览器环境中多个应用程序可以正常使用同一个Camera。但是,如果一个是在浏览器中运行,一个是独立应用程序,就不能共享使用同一个Camera,因为Camera不能被多个进程共享。

事件响应
在Camera有两个重要的事件响应
1. onStatus事件 muted属性变化会触发该事件
原参考手册中的一个示例可以说明onstatus的用法

01 : myCam = Camera .get ();
02 : myVideoObject.attachVideo(myCam);
03 : myCam.onStatus = function ( infoMsg ) {
04 : if ( infoMsg.code == 'Camera.Muted' )
05 : {
06 : trace ( 'User denies access to the camera' );
07 : }
08 : else
09 : trace ( 'User allows access to the camera' );
10 : }
11 : // Change the Allow or Deny value to invoke the function
12 : System .showSettings(0);



2. onActivity事件 视频是否活动的事件响应
请参考原手册的范例:

1 : // Assumes a Video object named 'myVideoObject' is on the Stage
2 : c = Camera.get();
3 : myVideoObject.attachVideo(c);
4 : c.setMotionLevel(10, 500);
5 : c.onActivity = function (mode)
6 : {
7 : trace(mode);
8 : };
 
FLASH COM学习笔记.10 MicroPhone对象
 
这一节讲述如何使用Microphone对象,包括怎么减少麦克风的回音。

获取麦克风
1 : Microphone.get([index]);
2 : //一般如果只有一个麦克风的话,可以用Microphone.get()

来自flashcomguru forums的检测麦克风函数:
01 : function checkforMic() {
02 : micArray = Microphone.names;;
03 : if (micArray.length >= 1){
04 : temp_mic = Microphone.get();
05 : if(temp_mic == -1)
06 : trace( '--- mic is detected but its busy' );
07 : else
08 : trace( '--- mic detected' );
09 : delete temp_mic;
10 : } else if (micArray.length == 0) {
11 : trace( '--- no Mic detected' );
12 : }
13 : }
14 :

或者使用下面的更简单的函数:
01 : function checkForMic(){
02 : return Microphone.names.length;
03 : }
04 :
05 : // trace ('User have a Mic? -> '+checkForMic());
06 :
07 : function isMicBusy(){
08 : if(arguments.length) return Microphone.get(arguments[0]) == -1;
09 : return Microphone.get() == -1;
10 : }
11 : // trace ('Is user's Mic busy? -> '+isMicBusy());


避免回音
如果你使用外置的话筒,因为会有较大的增益,就不可避免的遇到回音的问题。
为了尽量降低话筒的回音,FlashCom Server提供了回音抑制功能。要使用这一功能,可以通过下面的方法:
  1. myMicrophone.useEchoSuppression(true);

这样就可以保持较好的语音效果,而不会从话筒传递过多的的回音。但尽管如此,仍然会有部分的回音无法消除,下面是一些好的建议:
1. 适当调低你的话筒音量
2. 让话筒远离你的音箱
3. 及时查找你的设备故障
4. 如果可以尽量使用戴在头上的耳机或听筒

保持Microphone始终打开
为了节约带宽,FlashCom server默认会关闭Microphone对象当它不再使用的时候。但是,有时候你可能需要保持Microphone保持始终打开(例如为了保证没有任何延迟),你可以使用下面的方法:
  1. my_mic.setSilenceLevel(0)


音量调节
Flashcomguru上提供了如何调节音量的方法:
1 : //Attach your netstream audio to a movielcip:
2 : movieclip_mc.attachAudio(yournetStream);
3 : // create a sound object
4 : my_snd = new Sound(movieclip_mc);
5 : // to adjust the volume
6 : my_snd.setVolume(50);
 
FLASH COM学习笔记.11 NetConnection对象
 
对象简介
如果要把本地端的视频或者声音传递给其它的客户端,Flash影片就必须要联机到FlashCom 服务器。联机的方法就是通过NetConnect对象的connect()方法,连接到指定路径的FlashCom应用程序。
FlashCom使用RTMP协议来共享和传输你的数据、声音和视频。

对象属性:
isConnected 是否连接
uri 连接的URL地址,可以使用下面的方式
&S226; rtmp://www.myCompany.com/myMainDirectory/groupChatApp/HelpDesk
&S226; rtmpt:/sharedWhiteboardApp/June2002
&S226; rtmp::1234/chatApp/room_name

例如你要联机到vchat的聊天程序,并且进入room1房间,可以按照下面的方式写:
1 : //建立联机对象
2 : client_nc = new NetConnect ();
3 : //联机到应用程序实体
4 : client_nc.connect( 'rtmp://mywebsite.com/vchat/room1' );

可以不写房间名,则进入默认的房间
详细的连接语法可以参考我之前的笔记:连接示例

NetConnect对象并不支持http协议,所以类似下面的连接方式是错误的:
  1. myConn.connect('http://www.mydomain.com/myfile.php?id= 0001') ;

并且FlashCom服务器端不支持任何直接远程调用的方法如 getURL 或 LoadVars,也就是说,服务器端不能够和后台程序进行数据交换,必须使用call方法调用客户端方法或者使用FlashRemote(或者使用开源的PHPObject)。

远程呼叫
如果要呼叫远程服务器端的方法或指令,可以使用Call方法,该方法的格式如下:
1 : call (方法名称,接收传回值的对象(没有就用null),[参数1,参数2,...])
2 : //参数列表为需要传递到服务器端方法的参数,如果参数多余会被服务器端忽略

和很多对象一样,NetConnect对象有个onStatus事件,用于接受返回信息
下面是比较常见的写法:
1 : client_nc.onStatus = function (info){
2 : //处理状态信息的程序代码
3 : };
状态信息的类型记录在信息对象的level属性中,其可能值为
status 状态
warning 警告
error 错误
信息的内容则记录在对象的code属性中。在NetConnect对象中,可以参考下面的范例程序来输出返回信息:
01 : client_nc.onStatus = function (info){
02 : trace ( '信息类型:' + info.level + newline + '信息内容:' + info.code );
03 : switch (info.code){
04 : case 'NetConnection.Connect.Success':
05 : trace ( '联机成功!' );
06 : break;
07 : case 'NetConnection.Connect.Failed':
08 : trace ( '联机失败!' );
09 : break;
10 : case 'NetConnection.Connect.Closed':
11 : trace ( '联机中断!' );
12 : break;
13 : }
14 : };


保存日志
需要的话可以把连接日志记录下来:
1 : client_nc.onStatus = function(info)
2 : {
3 : _root.log += 'Recording stream status.\n' ;
4 : _root.log += 'Event: ' + info.code + '\n' ;
5 : _root.log += 'Type:' + info.level + '\n' ;
6 : _root.log += 'Message:' + info.description + '\n' ;
7 : }


关闭连接
要关闭连接请使用 close()方法,如下面的代码停止数据流对象后关闭连接
1 : function disconnect() {
2 : // Stops publishing the stream.
3 : srcStream.close();
4 : // Deletes the source stream connection.
5 : connection.close();
6 : }
 
FLASH COM学习笔记.12 NetStream对象
 
NetStream对象是在所有联机对象之间传递影音串流。如果你仅仅是为了传递文字聊天内容,使用共享对象就可以解决,不必要使用这个对象。
该对象的基本属性有
time 到目前为止,串流资料播放的秒数
bufferTime 缓冲区的最大秒数
currentFps 当前播放影像的速率(每秒帧数)
bufferLength 当前缓冲区的资料秒数
liveDelay 实时播放视频流的间隔
但是当你想知道当前播放的影像的总长度的时候,必须调用服务器端的方法才可以,因为客户端的FlashPlayer是无法获知数据流的总长的。你需要在客户端写如下方法:
01 : function getInfo()
02 : {
03 : nc.call( 'sendInfo', new MyResultSetName(), myStream);
04 : }
05 : function MyResultSetName()
06 : {
07 : this.onResult = function ( retVal )
08 : {
09 : _root.streamlength = retVal;
10 : };
11 : this.onStatus = function(info)
12 : {
13 : trace ( 'Level:' + info.level + 'Code:' + info.code);
14 : // process error object
15 : };
16 : }


然后在服务器端的main.asc文件中的相关事件中写入:
01 : application.onAppStart = function ()
02 : {
03 : trace('::: Application has started :::');
04 : }
05 : application.onConnect = function (client)
06 : {
07 : application.acceptConnection (client);
08 : // Add methods
09 : client.prototype.sendInfo = function (name) {
10 : var slen = Stream.length (name);
11 : trace ( 'slen:' + slen);
12 : return slen;
13 : };
14 : }


相关方法参考:
setBufferTime ( 秒数)
可以设置缓冲区的大小以提高低品质的网络情况
注意:bufferLength大小总是不大于bufferTime

attachVideo ( 影像来源,[ 拍摄模式 ] )
将摄像机对象的影像追加给串流对象,如果影像来源为null,将停止捕捉影像
拍摄模式省略表示捕捉连续的影像;若为0则只拍摄单元格画面;大于0,将以此数值为秒数间隔,连续拍摄单元格影像。

attactAudio ( 声音来源 )
将麦克风的音源设定给串流对象

publish ( 串流资料名,[ 播出方式 ])
如果串流资料名没有指定则停止播出
播出方式有live(默认值)实时播出但不存储;record 播出同时以串流资料名.flv文件存储,路径为应用程序路径下面的streams文件夹;append 播出的同时追加到指定名称的flv文件中,如果不存在,则自动创建。

pause()
暂停、开始播放

close ()
停止发布或播放当前所有数据流,把 NetStream.time 属性设置为 0, 使得其它客户端可以使用该数据流,该方法当你使用 NetStream.play() 或NetStream.publish() 的时候被隐含调用

play( 串流名称,起始时间,长度,是否清除前一个串流 )
起始时间默认值为-2 表示flash会先尝试播放实时影音,否则就播放指定识别名称的文件
若为-1 将只播放实时影音 若为0 将只播放指定名称的录像内容
长度参数指定影音播放的秒数 默认为-1 表示一直播放到结束 为其它值为播放到指定秒数的内容

receiveVideo(fps)
指定播放串流的速率fps设定为0时,flash将停止播放影像

seek(秒数)
快倒倒录像文件倒指定秒数的画面,如果设为0,则跳转到开头
可以使用相对时间来跳转,如
client_ns.seek(client_ns.time-3)

如果要在传输音频或视频流的同时,包含文本数据等,也就是说进行数据交换,则可以使用send方法。
可以在客户端包含下面的actionscript:
1 : var my_nc:NetConnection = new NetConnection();
2 : my_nc.connect('rtmp://myServer.myDomain.com/appName/appInstance');
3 : var my_ns:NetStream = new NetStream(my_nc);
4 : my_ns.publish('slav'
, 'live');
5 : my_ns.send('Fun', 'this is a test');

在接收端可以使用下面代码:
1 : var my_nc:NetConnection = new NetConnection();
2 : my_nc.connect('rtmp://myServer.myDomain.com/appName');
3 : my_ns = new NetStream(my_nc);
4 : my_ns.play('slav'
, -1, -1);
5 :
6 : my_ns.Fun = function(str) { //Fun is the handler name
7 : trace (str);
8 : }


关闭视频流的几种方法:
1 : myStream_ns.publish(false);// 停止整个串流
2 : myStream_ns.close();//关闭串流,当然也就停止了串流播放
3 : mystream_ns.attachVideo(null);//仅仅停止视频播放,仍然保持音频播放

更多的请期待FlashCom组件代码分析专题。
 
FLASH COM学习笔记.13 Video对象
 
视频对象用来显示实时的或者录制的视频流。视频对象显示的可以是通过Camera.get方法捕捉到的实时视频,也可以是通过NetStream.play方法播放的实时的或者录制的视频文件和MP3音频文件。
为了能够显示视频流,首先要放置视频对象到舞台,然后使用video.attachVideo方法附加视频流到视频对象即可。
1 : my_cam = Camera.get();
2 : my_video.attachVideo(myCam); // myVid 是放置到舞台的一个视频对象

视频对象的使用类似于MC,和其它可放置到舞台的对象一样,你可以设置不同的属性。视频对象的常用属性有:
width 视频对象的宽度
height 视频对象的高度
deblocking 是否使用deblocking过滤,默认为0自动适应,1为从不使用,2总是使用
smoothing 是否使用平滑过渡,默认为false不使用,true则使用平滑过渡(需要高品质播放模式)
下面的例子说明了如何发布、录制和回放视频
01 : // 实时播放的同时录制视频文件
02 : //录制的视频文件名为 'allAboutMe.flv'
03 : var my_nc:NetConnection = new NetConnection();
04 : my_nc.connect('rtmp://localhost/allAboutMe/mySpeech');
05 : var publish_ns:NetStream = new NetStream(my_nc);
06 : publish_ns.publish('allAboutMe', 'record');
07 : publish_ns.attachVideo(Camera.get());
08 :
09 : // 播放录制的视频文件
10 : // 注意:播放录制文件不需要再发布视频流
11 : var my_nc:NetConnection = new NetConnection();
12 : my_nc.connect('rtmp://localhost/allAboutMe/mySpeech');
13 : var subscribe_ns:NetStream = new NetStream(my_nc);
14 : subscribe_ns.play('allAboutMe');
15 : my_video.attachVideo(subscribe_ns); // my_video是一个视频对象实体


如果要清除当前的视频对象,可以使用clear方法
1 : my_video.clear();

需要注意的是,清除视频对象并不意味着中断连接,要中断数据流在视频对象中的播放,可以这样处理:
1 : my_video.attachVideo(null);
 
FLASH COM学习笔记.14 System对象
 
系统对象是Flash的一个顶层对象,主要用来设置系统参数和安全定义。
常用属性有:
System.useCodepage 是否使用网页字符格式,默认为false 格式是utf-8
System.exactSettings 访问本地设置是否使用超级域匹配规则 Flash7新增属性


常用的方法有:
System.showSettings( [panel] ) 显示系统设置对话框
0 隐私设置
1 本地存储设置
2 麦克风设置
3 摄像机设置
为空则显示用户最近设置

System.setClipboard( string ) 设置剪贴板文字 Flash7以后支持
用指定的字符串替换当前的剪贴板内容


system对象也具有onStatus事件响应,我们看下下面的代码:
01 : // 定义响应方法
02 : System.onStatus = function( genericError )
03 : {
04 : // Your script would do something more meaningful here
05 : trace('An error has occurred. Please try again.');
06 : }
07 :
08 : // 创建一个 NetStream 对象的方法
09 : // 如果NetStream 对象返回错误
10 : // System.onStatus 将被触发
11 :
12 : videoStream_ns.onStatus = function(infoObject) {
13 : if (infoObject.code == 'NetStream.Play.StreamNotFound') {
14 : trace('Could not find video file.');
15 : }
16 : }
 
FLASH COM学习笔记.15 客户端信息对象
 
在FlashCom中的Camera, Microphone, LocalConnection, NetConnection,NetStream和SharedObject对象都提供了onStatus事件响应,onstatus事件的返回信息记录在信息对象中。为了能够响应这些事件,你必须创建一个方法来处理信息对象,而最重要的一点是你必须要清楚不同的信息对象返回值和返回类型。
信息对象具有下面的属性。
code 记录信息的返回内容
level 信息等级状态,有status 状态 warning 警告 error 错误
下面对FlashCom中的对象的onstatus返回值作个总结。

Camera信息对象
Camera.Muted (Status)
用户拒绝使用camera
Camera.Unmuted (Status)
用户允许使用camera

LocalConnection信息对象
none (status)
none (error)

Microphone信息对象
Microphone.Muted (Status)
用户拒绝使用microphone.
Microphone.Unmuted (Status)
用户允许使用microphone.

NetConnect信息对象
NetConnection.Call.Failed (Error)
NetConnection.call方法调用服务器端的方法或命令失败
NetConnection.Connect.AppShutdown (Error)
服务器端应用程序已经关闭(由于资源耗用过大等原因)或者服务器已经关闭.
NetConnection.Connect.Closed (Status)
连接中断
NetConnection.Connect.Failed (Error)
连接失败
NetConnection.Connect.InvalidApp (Error)
指定的应用程序名称没有找到
NetConnection.Connect.Rejected (Error)
连接被拒绝
NetConnection.Connect.Success (Status)
连接成功

NetStream 信息对象
NetStream.Buffer.Empty (Status)
数据缓冲区为空
NetStream.Buffer.Full (Status)
缓冲区已慢
NetStream.Failed (Error)
传输中有错误发生
NetStream.Pause.Notify (Status)
播放暂停
NetStream.Play.Failed (Error)
播放出错
NetStream.Play.PublishNotify (Status)
发布开始,信息已经发送到所有订阅者
NetStream.Play.Reset (Status)
播放列表重置
NetStream.Play.Start (Status)
播放开始
NetStream.Play.Stop (Status)
播放停止
NetStream.Play.StreamNotFound (Error)
播放的实时流或文件不存在
NetStream.Play.UnpublishNotify (Status)
发布停止,信息已经发送到所有订阅者
NetStream.Publish.BadName (Error)
发布的数据流已经被发布
NetStream.Publish.Idle (Status)
发布者闲置过长
NetStream.Publish.Start (Status)
发布开始
NetStream.Record.Failed (Error)
录制文件出错
NetStream.Record.NoAccess (Error)
没有足够的文件访问权限
NetStream.Record.Start (Status)
文件录制开始
NetStream.Record.Stop (Status)
录制暂停
NetStream.Seek.Failed (Error)
数据流定位出错
NetStream.Seek.Notify (Status)
数据搜索定位成功
NetStream.Unpause.Notify (Status)
恢复播放
NetStream.Unpublish.Success (Status)
停止发布

ShareObject信息对象
SharedObject.BadPersistence (Error)
SharedObject.getRemote方法传递的参数不匹配
SharedObject.Flush.Failed Error
写入失败
SharedObject.Flush.Success (Status)
写入成功
SharedObject.UriMismatch (Error)
SharedObject.connect的url参数和SharedObject.getRemote方法不一致

注意:对于NetStream、NetConnect和远程共享对象而言,在联机情况下onStatus有更多的返回值,这些返回值将会在服务器端信息对象中介绍,其它对象无须联机也可以响应到返回值。

针对以上不同的对象可以指定各自的onstatus方法,Macromedia 在Flash中提供了一个“超级”函数叫做System.onStatus ,如果某个对象的onstatus响应的level属性是error,并且没有指定响应操作的时候,Flash会触发System.onStatus事件。
下面的例子演示了如何创建通用的或者特殊的方法来处理信息对象:
01 : //创建通用方法
02 : System.onStatus = function (genericError)
03 : {
04 : // 在这里写上详细的处理代码
05 : trace( 'An error has occurred. Please try again.' );
06 : };
07 : // 创建NetConnection对象的onstatus响应方法
08 : // 如果连接返回的值在响应事件中没有定义,并且是error等级的话
09 : // System.onStatus 事件会被响应
10 : nConn.onStatus = function (infoObject)
11 : {
12 : if (infoObject.code == 'NetConnection.Connect.Success' )
13 : {
14 : trace( 'Successful connection.' );
15 : }
16 : if (infoObject.code == 'NetConnection.Connect.Failed' )
17 : {
18 : trace( 'Connection failed.' );
19 : }
20 : };
21 : // Attempt to open connection
22 : nConn = new NetConnection();
23 : nConn.connect( 'rtmp://myServer.myDomain.com/myRTMPapp' );
 
FLASH COM学习笔记.16 SharedObject对象
 
我似乎反复的在讲共享对象了,实在是我觉得共享对象在FlashCom开发中太重要了,甚至可以说是FCS的灵魂。
之前的关于共享对象的文章可以参考我的笔记:
共享对象概述
理解共享对象
还有一篇转载的:共享对象

shared Object对象相当强大,他提供了在多个客户端实时数据共享,并且可以存储在客户端或远程服务器。可以把本地共享对象比作cookies,把远程共享对象看作实时的数据传输设备。
通常共享对象的使用方法如下:
1. 保持本地永久存储
这是最简单的共享对象应用。并且不需要FlashCom Server的支持。例如,你可以使用SharedObject.getLocal方法来创建一个本地共享对象。因为本地共享对象是永久存储的,用户端Flash结束的时候会通过data属性保存在客户端本地机器中。当下一次运行swf文件的时候,就可以直接存取到。如果你在影片播放结束的时候把共享对象的属性置空了,下一次就存取不到任何的值了。
2. 在服务器端共享和存储数据
存储在服务器端的共享对象数据可以被其它联机的客户端取到。例如,你打开了一个远程共享对象,该共享对象中存储了一个电话清单。当客户端对该共享对象数据有任何更改的时候,改变的数据对所有联机对象都是自同步的。如果对象暂时无法连接到服务器端,那么所作的更改将会在下一次更新到服务器端。
3. 实时交流数据
共享对象可以实时的在多个客户端之间共享数据。你可以打开一个存储实时数据的远程共享对象,例如,一个连接到聊天室的用户列表,当有用户进入或离开聊天室的时候,该共享对象会实时更新,所有连接到该服务器的客户端将立刻看到用户列表的更改。
下面的例子演示了一个简单的共享对象的使用,记住在创建一个远程共享对象之前,必须先使用NetConnect对象联机到服务器。
01 : // Create a local shared object
02 : so = SharedObject.getLocal('foo');
03 : // Create a remote shared object that is not persistent on the server
04 : nc = new NetConnection();
05 : nc.connect('rtmp://server.domain.com/chat/room3';
06 : so = SharedObject.getRemote('users', nc.uri);
07 : so.connect(nc);
08 : // Create a remote shared object that is persistent on the server
09 : // but not on the client
10 : nc = new NetConnection();
11 : nc.connect('rtmp://server.domain.com/chat/room3';
12 : so = SharedObject.getRemote('users', nc.uri, true);
13 : so.connect(nc);
14 : // Create a remote shared object that is persistent on the server
15 : // and on the client
16 : nc = new NetConnection();
17 : nc.connect('rtmp://server.domain.com/chat/room3';
18 : so = SharedObject.getRemote('users', nc.uri, '/chat');
19 : so.connect(nc);

规划远程共享对象
要规划远程共享对象,我们应该先设计一个数据管理模型。我们需要做的是数据字段设计和管理、冲突解决、客户端和服务器端的存储分析,我们针对这些方面一一说明。
如果要使用本地存储的远程共享对象,请确保swf的舞台尺寸大于215×138像素,否则将无法正常显示设置面板。
数据设计和管理
共享对象关联的数据存储在共享对象的data属性中,要设置共享对象的值可以使用下面的方式:
1 : //建立本地共享对象,没有则自动创建
2 : var so = SharedObject.getLocal('local_so');
3 : //为共享对象中的变量赋值
4 : so.data.userID = 'Liu21st';
5 : so.data.currentStatus = 'onLine';
6 : so.data.lastLogon = '2004-06-30';

如果要创建客户端的私有存储,可以不通过data属性,如:
1 : so.userID = 'Liu21st';
2 : so.currentStatus = 'onLine';
3 : so.lastLogon = '2004-06-30';

对共享对象的data属性赋NULL或undefined可以初始化字段
so.data.userID = NULL ;
但是并没有删除该字段,如果要删除请用:
delete so.data.userID;
我们也可以使用类似于
so.data.year.month.dayOfMonth = someValue;的方式来赋值
//注意该赋值并非一个字段 year.month.dayOfMonth
//而分别是给三个字段 year,month,dayOfMonth 初始化相同的值

但是不推荐使用该方式,因为这样在同步的时候会始终占用较多的带宽
使用分开赋值的方式可以避免每次同步全部数据
so.data.year = someValue;
so.data.month = someValue;
so.data.dayOfMonth = someValue;
你可以根据应用程序的需求来设计共享对象的变量。如果共享对象中的值都需要频繁更新,尽可能减少共享对象的字段可以提高性能。
站长经常使用的方式是:
1 : so.data.user = { id:1,sex:b,name:liu21st }
2 : // 在存取的时候可以使用
3 : // so.data.user.name的方式


冲突解决
如果多个客户端在同时更新数据的话,冲突就产生了。必须制定冲突解决策略,下面是常用的方法。
1. 尽量使用不同的字段
最简单的方法是给每个客户端或服务器端分配不同的字段。例如,为聊天室中的每个用户设定一个字段,并且每个用户只能更改自己的字段。
2. 分配拥有者
更高级的策略是分配一个客户端作为共享对象属性的短期拥有者,你可以锁定对象的属性被写入,在有其它客户端对该属性的更新时候向拥有者发送请求。如果请求成功,表示只有一个客户端更改该共享对象数据。
3. 通知客户端
当服务器拒绝客户端的更改请求的时候,SharedObject.onSync事件会通知客户端该更改暂时被拒绝,然后,应用程序可以提供一个用户界面让用户再次发送。这个策略比较适用于不定期更新的数据,还有一个好处是当冲突发生时,客户端可以选择接收或拒绝更改。
4. 选择性更改
某些应用程序按照“先到先服务”的原则来定制策略,这种方式适用于用户可以重新递交同步请求当其他人更新完成之后。
本地存储空间的考虑
你可以选择让远程共享对象存储在客户端、服务器或者两者,本地共享对象总是存储在本地客户端,直到没有可用空间为止。
默认的存储空间大小是100K,如果企图存储更多的数据,Flash会弹出一个本地存储对话框,让用户允许或拒绝本地存储。
如果用户选择允许,数据将被保存,并且SharedObject.onStatus事件触发,返回的code属性值为 SharedObject.Flush.Success,如果选择拒绝,数据存储失败,code属性值为SharedObject.Flush.Failed,用户也可以选择打开本地存储面板,进行存储空间大小设置,并且记住当前的选择。
在actionscript中无法设置本地存储空间的大小,必须通过弹出对话框的形式让用户操作,如果需要,请使用:
System.showSettings(1)

共享对象的方法总结
SharedObject.close
//关闭远程共享对象和服务器的连接
SharedObject.connect
//连接到服务器端的一个远程共享对象
SharedObject.flush
//立即写入本地共享对象数据
//如果不使用系统会在下列情况自动完成写入
// swf文件关闭,sharedObject.close调用,共享对象被回收
// 如果对远程共享对象使用该方法,只会在客户端写入,而不会在服务器端写入,如果要完成服务器端的写入请使用下面的代码:
01 : // This is a SERVER-SIDE script, not ActionScript
02 : // Get the shared object when the application is loaded.
03 : application.onAppStart = function()
04 : {
05 : application.mySO = SharedObject.get( 'SharedObjName' , true);
06 : }
07 : // When a user disconnects, flush the shared object.
08 : application.onDisconnect = function(client)
09 : {
10 : application.mySO.flush();
11 : }
12 : // You can also set a timer to periodically flush the shared object
13 : // onto the hard disk on the server
14 : application.onAppStart = function()
15 : {
16 : application.mySO = SharedObject.get( 'SharedObjName' , true);
17 : setInterval(function() { application.mySO.flush(); }, 60000);
18 : }

SharedObject.getRemote
//创建一个远程共享对象
SharedObject.getSize
//取得当前(本地或远程)共享对象的字节大小
//var soSize= this.so.getSize();
SharedObject.send
//对所有联机用户广播消息
01 : // Create a remote shared object called remoteSO
02 : // Place an Input Text text box named inputMsgTxt on the Stage
03 : // Attach this code to a button labeled 'Send Message'
04 : on (release) {
05 : _root.remoteSO.send( 'testMsg' ,inputMsgTxt);
06 : }
07 : // Attach this code to the frame containing the button
08 : _root.remoteSO.testMsg = function(recvStr)
09 : {
10 : trace(recvStr);
11 : }
12 : // Type data in the text box and press the button to see the results

SharedObject.setFps
//设定客户端更新的速率

共享对象的创建方法
SharedObject.getLocal(对象名称);//不需要服务器端支持,只用于本地存储
01 : // Get the kookie
02 : so = sharedobject.getlocal( 'kookie' );
03 : // Get the user of the kookie and go to the frame number saved for this user.
04 : if (so.data.user != undefined) {
05 : this.user = so.data.user;
06 : this.gotoAndStop(so.data.frame);
07 : }
08 : The following code block is placed on each movie frame.
09 : // On each frame, call the rememberme function to save the frame number.
10 : function rememberme() {
11 : so.data.frame=this._currentFrame;
12 : so.data.user= 'John' ;
13 : }

SharedObject.getRemote(对象名称,联机网址);//建立暂存的远程共享对象,重启即失效
1 : conn = new NetConnection();
2 : conn.connect( 'rtmp://somedomain.com/applicationName' );
3 : myObject = SharedObject.getRemote( 'mo' , conn.uri, false);
4 : myObject.connect(conn);

SharedObject.getRemote(对象名称,联机网址,true);//远程共享对象数据存入服务器,在服务器端会保存'对象名称.fso'文件

共享对象的属性
data属性(不再详述)
共享对象的方法
共享对象的事件
SharedObject.onStatus //共享对象返回错误、警告或状态的事件
SharedObject.onSync //同步事件

下面的实例可以参考:
01 : function getMaster()
02 : {
03 : trace( 'getMaster called' );
04 : master = SharedObject.getRemote( 'master' , con.uri, true);
05 : connVal = master.connect(con);
06 : if (connVal) print ( 'Connection was successful' );
07 : else print( 'Unable to connect the shared object with the given NetConnection object' );
08 : master.onSync = function (listVal) {
09 : getPlayList();
10 : trace( 'SO: ' + so.data[currentPlaylist]);
11 : }
12 : }
 
FLASH COM学习笔记.17 应用程序设计和开发
 
这篇内容主要讲述在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 : }

然后,在其它文件中,包含下面代码:
#i nclude '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 : }
区别就在于其它文件包含该文件的时候不使用#i nclude指令,而是使用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。当用户改变了带宽限制后,摄像头和麦克风设置也会更新,还有一个不引人注意的地方,就是updateBandwidth方法也会根据设置的选择改变屏幕的尺寸。
01 : _root.Modem_btn.onPress = function() {
02 : // Call updateBandwidth to change
03 : // camera and mic settings and inform
04 : // the server
05 : _root.updateBandwidth(1);
06 : }
07 : _root.DSL_btn.onPress = function() {
08 : _root.updateBandwidth(2);
09 : }
10 : _root.LAN_btn.onPress = function() {
11 : _root.updateBandwidth(3);
12 : }

在fla文件的第一帧,你可以找到下面一段代码,用来初始化摄像头和麦克风,以及从服务器播放串流和根据用户的选择更新摄像头、麦克风的设置。
01 : #i nclude '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 updateBandwidth(b) {
33 : // Respond to a change in the bandwidth
34 : // If 'Modem' was selected
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 selected
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 selected
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 : // selection, 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/ 目录。
 
FLASH COM学习笔记.18 良好的编程习惯
 
本节内容概述了在使用actionscript编程和创建应用程序的时候需要遵循的一些规则,以及如何使我们的程序代码更有效和具有更好的可读性,更方便调试应用程序。
把这节写在前面,也是为了让开始接触ActionScript编程的开发人员从一开始就养成好的编程和开发习惯。
1. 遵循命名规则
一个应用程序的命名规划必须保持一致性和可读性。任何一个实体的主要功能或用途必须能够根据命名明显的看出来。因为ActionScript是一个动态类型的语言,命名最好是包含有代表对象类型的后缀。一般而言,名词_动词和形容词_名词之类的语法是最常用的命名方式,如:
影片名字:my_movie.swf
URL实体:course_list_output
组件或对象名称:chat_mc
变量或属性:userName
方法和变量的名称应该以小写字母开头,对象和对象的构造方法应该大写。命名变量的时候使用大小写混和的方式,并且使用字母打头,还可以包含数字和下划线。
下面的一些命名是非法的:
_count =5 ;//首字符不能使用下划线
5count = 0;//首字符不能使用数字
foo/bar = true;//包含非法字符
另外,ActionScript使用的保留字不能用来命名变量。
ActionScript是基于ECMAScript,所以我们可以根据ECMAScript的规范来命名。如,
course_list_output = 'foo'; //全部小写,使用下划线分割字串
courseListOutput = 'foo'; // 大小写混和的方式
BASEURL = http://www.foo.com; // 常量使用全部大写
MAXCOUNTLIMIT = 10;
MyObject = function(){ }; // 构造函数
f = new MyObject(); // 对象
注意;良好的命名规范还可以使用Flash的代码提示功能。

2. 给你的代码添加注释
  使用代码注释能够使得程序更清晰,也便于我们阅读。Flash支持的代码注释方法有两种:
 单行注释,通常用于变量的说明
var clicks = 0; // variable for number of button clicks
 多行注释,通常用于功能说明和大段文字的注释:
/*
Initialize the clicks variable that keeps track of the number of times
the button has been clicked.
*/
一些具有特定意思的注释方法:
// :TODO: topic
表明一个主题的开始
// :BUG: [bugid] topic
显示了一个BUG所在
// :KLUDGE:
表明下面的代码并不完善,可能存在问题
// :TRICKY:
告诉开发人员下面的代码具有相互作用,修改之前请谨慎

3. 保持代码的整体性
无论什么情况,应该尽可能保证所有代码在同一个位置,这样使得代码更容易搜索和调试。我们在调试程序的时候很大的困难就是定位代码,如果大部分代码都集中在同一帧,问题就比较好解决了。通常,我们把代码都放在第一帧中,并且单独放在最顶层。如果在第一帧中集中了大量的代码,记得用注释标记区分,并在开头加上代码说明。
1 : //===========================================
2 : // 视频语音聊天系统
3 : // FCAVPresence组件
4 : // Copyright ◎2002 Macromedia, Inc. All rights reserved.
5 : // 完 善: Liu21st, Liu21st@126.com
6 : //---------------------------------------------------------


在独立的功能模块前面加上类似的标注:
1 : //===========================================
2 : // 参数初始化
3 : //---------------------------------------------------------


4. 初始化应用程序
记得一定要初始化你的应用程序,init函数应该是你的应用程序类的第一个函数,如果使用面向对象的编程方式则应该在构造函数中进线初始化工作。该函数只是对应用程序中的变量和对象初始化,其它的调用可以通过事件驱动。
下面的例子可以说明如何进线初始化
1 : function FCAVPresenceClass() {
2 : this.init();
3 : }
4 : FCAVPresenceClass.prototype.init = function() {
5 : this.name = (this._name == null ? '_DEFAULT_' : this._name);
6 : this.prefix = 'FCAVPresence.' + this.name + '.';
7 : };


5.使用局部变量
所有的局部变量使用关键字var来申明,这样可以避免被全局变量访问,更重要的是,可以保证变量不被覆盖和混淆程序逻辑。例如,下面的代码没有使用var来申明,覆盖了其它变量。
01 : counter = 7;
02 : function loopTest()
03 : {
04 : trace(counter);
05 : for(counter = 0; counter < 5; counter++)
06 : {
07 : trace(counter);
08 : }
09 : }
10 : trace(counter);
11 : loopTest();
12 : trace(counter);
输出结果为:
7
7
0
1
2
3
4
5

6. 创建对象时使用原型添加方法和属性
当我们创建一个对象的时候,应当使用原型方式来添加对象的方法或属性,使得该方法或属性能够被所有该对象或子对象的实体所访问。这种能够确保内存中每个函数只有一份拷贝。作为一般的规则,不要在构造函数中定义方法。下面是一个正确的例子:
01 : // Best practice for creating an object
02 : MyObject = function()
03 : { }
04 : MyObject.prototype.name = '';
05 : MyObject.prototype.setName = function(name)
06 : {
07 : this.name = name;
08 : }
09 : MyObject.prototype.getName = function()
10 : {
11 : return this.name;
12 : }


下面这段代码是不可取的:
01 : // Less desirable practice for creating an object
02 : MyObject = function()
03 : {
04 : this.name = '';
05 : this.setName = function(name)
06 : {
07 : this.name = name;
08 : }
09 : this.getName = function()
10 : {
11 : return this.name;
12 : }
13 : }
使用上面的方式在每个对象的实体被创建的时候都会实体重新复制每一个属性和方法,会加重系统的内存开销。

7. 规范命名方式获取代码提示功能
这方面我已经有过详细的叙述,请看:
[ actionscript代码提示功能 ]和 [ 面向对象方式的代码提示功能 ]
 
FLASH COM学习笔记.19 服务器管理-Actionscript API
 
FlashCom Server MX 1.5 包含了服务器管理的ActionScript API,提供了一些高级的方法集用来扩展管理控制台,让我们可以自己开发Flash应用程序的管理和监视工具。

使用服务器管理ActionScript API
为了使用服务器管理ActionScript API,你必须安装有FlashMX和FlashCom server,并且具有FlashCom Server的管理权限。当然,你还能很熟练的用ActionScript来编写Flash应用程序。
掌握服务器管理ActionScript API最好的方法是查看管理控制台的源代码。注册用户可以在Macromedia的下载中心下载到admin.fla文件。

建立服务器连接
FlashCom Server的默认端口是1935,但是,为了使用服务器管理Actionscript API,你必须连接到管理端口,默认1111。连接服务器的方式和Flashcom应用程序一样使用
NetConnect.connect方法,不同的是需要传递三个参数:服务器管理目录的url,管理员用户名,管理员密码。有效的管理员名称和密码是在配置文件Server.xml中定义的。下面是连接示例:
1 : nc = new NetConnection();
2 : nc.connect('rtmp://localhost:1111/admin', 'admin', '1234');
为了使用更安全的用户认证机制,建议使用防火墙控制对1111端口。[笔者注:更多的关于安全方面的内容以后会专门叙述]

语法示例
要使用服务器端ActionScript API 的方法,你必须使用call指令并使用相应的参数。
下面的示例中,getAppStats方法被调用,并由new receiveAppStats事件处理反馈信息,ChatApp是该方法需要传递的应用程序名参数。
1 : nc = new NetConnection();
2 : nc.connect('rtmp://localhost:1111/admin', 'MHill', '635xjh27');
3 : // Call getAppStats
4 : nc.call('getAppStats', new receiveAppStats(), 'ChatApp');


一个简单的应用程序例子
下面的例子调用了getAppStats方法来查看服务器的应用程序chatApp的状态
appName 是一个文本输入框的实例名
outputBox 是返回结果的文本框实例名
01 : /** Establishes the connection to Flash Communication Server **/
02 : nc = new NetConnection();
03 : nc.connect('rtmp://localhost:1111/admin','admin_name','admin_pass');
04 : /** Makes the API call, for example, 'GetAppStats' **/
05 : function doGetAppStats() {
06 : function onGetAppStats()
07 : {
08 : this.onResult = function(info)
09 : {
10 : if (info.code != 'NetConnection.Call.Success')
11 : outputBox.text = 'Call failed: ' + info.description;
12 : else {
13 : outputBox.text = 'Info for '+appName.text+ ' returned:' + newline;
14 : printObj(info, outputBox);
15 : }
16 : }
17 : }
18 : nc.call('getAppStats'
, new onGetAppStats(), appName.text);
19 : }
20 : // This function proceeds through an object, printing all values to the
21 : // destination, including recursively printing objects within objects.
22 : // The tabLevel parameter is used for cosmetic purposes.
23 : function printObj(obj, destination, tabLevel)
24 : {
25 : if (arguments.length < 2) {
26 : trace('ERROR! you need to supply a text object to output to');
27 : return;
28 : }
29 : if (arguments.length < 3)
30 : tabLevel = 0;
31 : for (var prop in obj) {
32 : for (var i = 0; i < tabLevel; i++) // insert requested # of tab characters
33 : destination.text += '\t';
34 : destination.text += prop + ' = ' + obj[prop] + newline;
35 : if (typeof (obj[prop]) == 'object') { // recursively call printObj
36 : printObj(obj[prop], destination, tabLevel+1 );
37 : }
38 : }
39 : }
40 : // Alerts you if there are errors connecting to the server.nc.onStatus =
41 : function(info) {
42 : if (info.code == 'NetConnection.Connect.Success') {
43 : trace('Connected! The call should work'
)
44 : } else {
45 : // use nc.isConnected to test condition of server
46 : if (! nc.isConnected)
47 : trace('NO netConnection to server. Call will not work');
48 : }
49 : }


服务器端信息对象
所有服务器端ActionScript API 方法返回值都都保存在信息对象的相关属性中,这些属性和客户端的信息对象属性有所区别,分别是:level, code, timestamp, data, description和 details。其中level, code和 timestamp 属性是全部都具备的,其它属性是某些方法才具有的。data属性通常用来返回对象或数组数据,description和details属性通常提供一些错误信息。

方法总结
服务器管理ActionScript API包含了三种类型的方法:
查询方法:查看你的FlashCom服务器、应用程序和指定的应用程序实例的状态信息;
管理方法:对Flashcom服务器的用户管理、服务器管理和应用程序管理等
配置方法:查看和设置服务器的配置文件
有些方法只有管理员才有权限操作(用*号注明),虚拟主机的管理员不能够使用这些方法。

查询方法概要
01 : getActiveInstances 返回包含所有正在运行中的应用程序实例名的数组
02 : getAdaptors Returns an array of adaptor names.
03 : getAdminContext Returns the administrative context for the administrator (administrator type, name of
04 : adaptor, and name of the virtual host).
05 : getApps 返回所有应用程序的名称数组
06 : getAppStats 返回指定应用程序的所有实例的集合信息
07 : getInstanceStats 返回当前运行的应用程序实例的详细信息
08 : getIOStats 返回 I/O 信息 *
09 : getLicenseInfo 返回license 信息
10 : getLiveStreams 返回指定应用程序当前发布的所有实时串流信息
11 : getLiveStreamStats 返回串流的详细信息
12 : getMsgCacheStats 返回服务器TCMessage缓存状态信息.
13 : getNetStreams 返回当前连接到应用程序的所有的NetStream列表
14 : getNetStreamStats 返回指定NetStream的详细信息.
15 : getScriptStats 得到指定应用程序实例的脚本运行信息
16 : getServerStats 取得服务器状态和统计信息*
17 : getSharedObjects 返回当前应用程序实例的所有共享对象数组
18 : getSharedObjectStats 返回共享对象的详细信息
19 : getUsers 返回连接当前到应用程序实例的所有用户数组
20 : getUserStats 返回指定用户的详细信息
21 : getVHosts 返回虚拟主机的数组
22 : getVHostStats 返回虚拟主机的统计信息
23 : ping 返回服务器状态标记的信息

管理方法概要
01 : addAdmin 添加一个系统管理员*
02 : addApp 添加一个新的应用程序(会自动创建目录)
03 : changePswd 更改管理员密码
04 : gc 强制服务器端的资源垃圾回收*
05 : reloadApp 重启应用程序,会先卸载该应用程序的实例
06 : removeAdmin 删除管理员*
07 : removeApp 删除应用程序或应用程序实例
08 : restartVHost 重启虚拟主机
09 : startServer 启动FlashCom Server*
10 : startVHost 启动指定的虚拟主机*
11 : stopServer 停止FlashCom Server*
12 : stopVHost 停止虚拟主机
13 : unloadApp 卸载应用程序以及所有实例,端口用户连接

配置方法概要
1 : getConfig 返回指定配置键的配置信息
2 : setConfig 设置指定的配置键

关于每个方法的详细资料请参考手册中的说明。
 
FLASH COM学习笔记.20 拍摄和创建影片场景
 
这一节讲述如何通过FlashCom Server来实现拍摄和创建影像索引功能,这个技术对于需要保存影像数据非常有用。
拍摄功能
我们在NetStream.attachVideo 的方法中已经提到过
myStream.attachVideo(source | null [ , snapShotMilliseconds ])
snapShotMilliseconds参数就是用来设置抓屏的时间间隔,如果设置成0,表示只抓取一个单元格画面,如果大于0的话,就表示以该秒数为时间间隔,连续拍摄单元格影像。
下面我们来看下FlashCom自带的一个范例 doc_snapshot.fla的拍摄功能的实现。
01 : #i nclude 'NetDebug.as'
02 : // Recording state variable
03 : RecState_box.text = 0;
04 : // Number of snapshots
05 : numSnaps = 0;
06 : // Initialize button label
07 : Record_btn.setLabel('Record');
08 : // Connect to the snapshot app and get connection status
09 : function doConnect() {
10 : client_nc = new NetConnection();
11 : client_nc.onStatus = function(info) {
12 : trace('Level: ' + info.level + newline + 'Code: ' + info.code);
13 : };
14 : client_nc.connect('rtmp:/doc_snapshot/room_01');
15 : }
16 : // Create a stream for recording and getting the snapshot
17 : function initStreams() {
18 : // Stream for recording
19 : out_ns = new NetStream(client_nc);
20 : out_ns.onStatus = function(info) {
21 : trace('Level: ' + info.level + newline + 'Code: ' + info.code);
22 : };
23 : // Stream for playing
24 : in_ns = new NetStream(client_nc);
25 : in_ns.onStatus = function(info) {
26 : trace('Level: ' + info.level + newline + 'Code: ' + info.code);
27 : };
28 : }
29 : // Get a camera instance and attach it to the local
30 : // video, Live_video, and the output stream
31 : client_cam = Camera.get();
32 : Live_video.attachVideo(client_cam);
33 : // Button event handler for publishing and showing the snapshot
34 : function doRecord() {
35 : // If you’re not recording, begin to record
36 : if (RecState_box.text == 0) {
37 : // Clear the snapshot window
38 : Snapshot_mc.removeMovieClip();
39 : // 关键的实现代码
40 : //拍摄一个单元格画面
41 : out_ns.attachVideo(client_cam, 0);
42 : out_ns.publish('myRecording'+numSnaps, 'record');
43 : // Set the label to stop
44 : Record_btn.setLabel('Stop');
45 : // Update the recording state
46 : RecState_box.text = 1;
47 : // If you’re recording, stop
48 : } else {
49 : // Stop publishing recorded stream
50 : out_ns.publish(false);
51 : // Close the stream so that we can use the same to publish again
52 : out_ns.close();
53 : // Set the label to 'Record'
54 : Record_btn.setLabel('Record');
55 : // Update the recording state
56 : RecState_box.text = 0;
57 : showSnapshot();
58 : }
59 : }
60 : // Show the snapshot by attaching the stream to the SnapView_video
61 : // video object and playing it
62 : function showSnapshot() {
63 : // Create a new movie clip from the exportable movie clip View_mc,
64 : // which contains a video object, SnapView_video. Provide a new name, and
65 : // depth (a number relative to the other View_mcs on the stage used
66 : // to prevent collision)
67 : _root.attachMovie('View_mc'
, 'Snapshot_mc', numSnaps);
68 : // Attach the input stream to the SnapView_video video object
69 : // in the v instance of the View_mc movie
70 : Snapshot_mc.SnapView_video.attachVideo(in_ns);
71 : Snapshot_mc._x=375;
72 : Snapshot_mc._y=225;
73 : // Play the recording
74 : in_ns.play('myRecording'+numSnaps);
75 : // Update the counter for the number of snapshots for next time.
76 : numSnaps++;
77 : }
78 : // Connect to the server
79 : doConnect();
80 : // Initialize the streams
81 : initStreams();

创建影像索引
影像索引是创建原始的影像的缩略查看,类似于拍摄功能,都提供了单帧的影像数据,区别在于拍摄功能是获取一帧影像,而影像索引一般是播放录制影像的第一帧。
在前面的例子中,我们通过设置snapShotMilliseconds参数来得到影像的拍摄,在下面的例子中,我们还需要使用NetStream.play方法来实现播放单一帧:
thumbStream.play('myRecording', 0, 0, true)
中间两个参数表示播放的开始和结束位置(0,0 表示从头开始播放一帧),最后一个参数表示是否中断之前的播放。
下面我们来参考下FlashCom的范例doc_thumbnails.fla 的实现方式。
01 : #i nclude 'NetDebug.as'
02 : // Recording state variable
03 : recState = 0;
04 : // Initialize button label
05 : Record_btn.setLabel('Record');
06 : // Show the recording in a thumbnail
07 : showThumb();
08 : // Connect to the thumbnails app and get connection status
09 : function doConnect()
10 : {
11 : client_nc = new NetConnection();
12 : // If connection is closed, clear the History and the list
13 : // Handle status message
14 : client_nc.onStatus = function(info) {
15 : trace('Level: ' + info.level + newline + 'Code: ' + info.code);
16 : }
17 : client_nc.connect('rtmp:/doc_thumbnails/room_01');
18 : }
19 : // Create a stream for recording and getting the thumbnail
20 : function initStreams()
21 : {
22 : out_ns = new NetStream(client_nc);
23 : out_ns.onStatus = function(info)
24 : {
25 : if (info.code == 'NetStream.Publish.Success') {
26 : var description = 'You have published.';
27 : trace(description);
28 : }
29 : };
30 : thumb_ns = new NetStream(client_nc);
31 : }
32 : // Get a camera instance and attach it to the local
33 : // video, Live_video, and the output stream
34 : function initMovie()
35 : {
36 : client_cam = Camera.get();
37 : Live_video.attachVideo(client_cam);
38 : out_ns.attachVideo(client_cam);
39 : }
40 : // Button event handler for publishing and showing the thumbnail
41 : function doRecord()
42 : {
43 : if (recState == 0) {
44 : out_ns.publish('myRecording'
, 'record');
45 : Record_btn.setLabel('Stop');
46 : recState = 1;
47 : } else {
48 : out_ns.publish(false);
49 : Record_btn.setLabel('Record');
50 : recState = 0;
51 : showThumb();
52 : }
53 : }
54 : // Show the thumbnail by attaching the stream to the ThumbView_vc
55 : // video object and playing it
56 : function showThumb()
57 : {
58 : ThumbView_vc.attachVideo(thumb_ns);
59 : thumb_ns.play('myRecording'
, 0, 0, true);
60 : }
61 : // Connect to the server
62 : doConnect();
63 : // Initialize the streams
64 : initStreams();
65 : // Initialize the movie
66 : initMovie();
 
FLASH COM学习笔记.21 Client对象
 
Client对象包含了每个联机用户的信息,例如:客户端的IP地址、Flash和操作系统的信息、分配用户的频宽以及呼叫客户端的函数。该对象必须在服务器端使用。
Clinet对象经常用来呼叫客户端定义的方法,使用Client.call方法
例如我们在客户端定义了一个获取随机数的方法
1 : nc = new NetConnection();
2 : nc.connect ('rtmp://someserver/someApp/someInst');
3 : nc.random = function(){
4 : return (Math.random());
5 : };

需要在服务器端使用该方法时,就可以通过client对象的call方法
01 : application.onConnect = function(clientObj){
02 : trace('we are connected');
03 : application.acceptConnection(clientObj);
04 : clientObj.call('random', new randHandler());
05 : };
06 : randHandler = function(){
07 : this.onResult = function(res){
08 : trace('random num: ' + res);
09 : }
10 : this.onStatus = function(info){
11 : trace('failed and got:' + info.code);
12 : }
13 : };

第二个参数是返回对象,如果有参数需要传递,依次跟在后面就可以了。
Client对象可以方便地获取某个客户端的相关信息,包括:
Client.agent 客户端的平台和版本信息
Client.ip 客户端的 IP 地址
Client.protocol 客户端连接到服务器的协议
Client.readAccess 客户端具有读操作的权限列表
Client.referrer 客户端swf文件的URL地址
Client.writeAccess 客户端具有写操作的权限列表
使用方法如下:
1 : application.onConnect = function(client){
2 : if (client.ip == '127.0.0.1'){
3 : // insert code here
4 : } else {
5 : // insert code here
6 : }
7 : };

请注意不要和application.clients属性相混淆,application.clients是所有联机用户的列表
application.clients[ i ]表示某个Client对象的实例
我们可以这样访问客户端对象的属性,
1 : for (var i = 0; i < application.clients.length; i++) {
2 : trace(application.clients[ i ].ip);
3 : }


关于限制带宽的两个方法
Client.getBandwidthLimit 取得带宽限制值,分别取得客户端到服务器端以及服务器端到客户端的带宽限制,如:
1 : application.onConnect = function(newClient){
2 : var clientToServer= newClient.getBandwidthLimit(0);
3 : var serverToClient= newClient.getBandwidthLimit(1);
4 : };

Client.setBandwidthLimit(iServerToClient,iClientToServer) 设置带宽限制值
如果某个参数设为0,表示不改变当前的设置值。
查询客户端是否和服务器保持连通状态可以使用Client.ping方法,如
1 : application.onConnect( newClient ) {
2 : if ( newClient.ping() ){
3 : trace('ping successful');
4 : }
5 : else {
6 : trace('ping failed');
7 : }
8 : }

注意有时候ping方法的响应时间比较久,要最有效的侦测客户端是否和服务器端保持连通的方法是client和server端作相向回覆。
如果所有的客户端对象的实例都需要使用相同的属性和方法的时候,你可以把该属性和方法扩展到类中,而不需要在客户端为每一个实例创建方法。这样可以减少客户端的内存占用。这个过程称为类的扩展,你可以扩展任何客户端或服务器端的类。
扩展的方法或属性不需要在类的架构函数中声明(在架构函数中声明的方法和属性在每个实例初始化的时候都会分配一次),通过prototype属性来扩展的方法和属性在所有类的实体中都可以使用。
下面我们来看个例子,
1 : application.onConnect = function(clientObj){
2 : clientObj.birthday = myBDay;
3 : clientObj.calculateDaysUntilBirthday = function(){
4 : // insert code here
5 : }
6 : };
如果你希望一些方法和属性能够被所有application.clients数组中的客户端使用,而不需要每次都定义。我们就可以通过对Client对象扩展,我们首先定义好需要的方法
1 : function Client_getWritePermission(){
2 : return this.writeAccess;
3 : }
4 : function Client_createUniqueID(){
5 : var ipStr = this.ip;
6 : var uniqueID = 're123mn'
7 : return uniqueID;
8 : }

然后给Client对象的prototype属性添加我们定义的方法
1 : Client.prototype.getWritePermission = Client_getWritePermission;
2 : Client.prototype.createUniqueID = Client_createUniqueID;
3 :
你也可以添加属性给Clent对象,如
Client.prototype.company = 'Macromedia';
这些方法和属性对于任何一个Client对象的实例都时可用的。
1 : application.onConnect = function(clientObj){
2 : var clientID = clientObj.createUniqueID();
3 : var clientWritePerm = clientObj.getWritePermission();
4 : };
 
FLASH COM学习笔记.22 Flash Com Framework
 
FlashCom的Framework写的很不错,对深入研究actionscript和flashcom都有一定帮助。
把function的几篇相关文章摘读一下
原文出处:http://blog.funciton.com/en/archives/000254.php
本人对原文做了部分删减,增加了一些原文没有的代码参考。

第一部分
MM的FlashCom Server Framework原本是和组件相关联的,但是其中添加了不少有用的功能,我们依然可以在不使用FlashCom组件的情况下来使用该Framework(Function组件就是一个例子)。
一个FlashCom Server只能运行一个application对象以及相关事件,比如说,我们只能在main.asc文件中定义一个application.onAppStart, application.onConnect等,但问题是,我们如何管理每个组件类的私有应用程序事件。
下面我们来一步一步揭开Framework的神秘面纱。
Framework怎样对应用程序对象建立广播(类似于FlashMX2004中的EventDispatcher 类和Flash MX中的AsBroadcaster对象)?
它的方式是否就像是一个应用程序事件通过广播调用和调用所有的对象事件?
那么这些组件放置在gFrameworkFC对象的什么地方?
注:gFrameworkFC对象是由Framwork建立的一个全局对象
每一个组件实例都基于gFrameworkFC对象中的components对象,如果有更多的对象被建立会是什么情况?
它们通过基于服务器端类的命名空间放置在不同的位置,并且可以实例化。
例如:FCChat组件类的命名空间是
gFramework.components.FCChat.clientSideComponentInstance
如果我们有多个chat组件,FCChat对象需要两个属性来指向不同的组件实例。
我们没有涉及到客户端的组件实例,事实上我们仅仅需要操作服务器端对象而无需直接操作客户端对象。
Framework具有下面些常用的对象
gFrameworkFC 全局对象
clientGlobals 客户端全局对象
components 组件对象


第二部分
我们都知道服务器端的参数不能传递一个真正的数组,我们需要把数据连接起来,这给我们传值带来很大的不便。
事实上FlashCom的工程师通过Framework解决了这个问题,他们尝试过很多种方法,直到FlashCom1.5 updater1出来后,这个问题才真正的解决。通过gFrameworkFC全局对象的__toarray__方法,究竟如何使用呢,我们先来看下该方法的定义。
1 : gFrameworkFC.__toarray__ = function(obj) {
2 : if ( typeof(obj) != 'object' || obj.constructor == Array || obj[ 'length' ] == null )
3 : return obj;
4 : var a = new Array(obj.length)
5 : for ( var i = 0; i < obj.length; i++ )
6 : a[ i ] = obj[ i ];
7 : return a;
8 : }

使用的时候我们只需要通过调用对象的arguments参数,通过__toarray__方法返回一个真正的数组对象。如:
1 : application.onConnect = function (){
2 : // arguments is not a real array
3 : var t = gFrameworkFC.__toarray__( arguments );
4 : }

这样,t就是一个数组,我们可以对它进行诸如concat, splice, pop, push之类的数组操作了。
另外一个很重要的地方是,每个连接的客户端对象都将通过Framework赋予一个唯一的ID,当应用程序重新启动的时候这个ID的值初始化为 0 ,这个ID被getClientGlobals和getClientLocals方法所调用,这在下个部分会详细描述。
你可以通过__ID__ 属性来访问,如果你使用服务器端组件的话,也可以使用下面的方式访问到
1 : //FCMySSComponent是服务器端的组件实例名
2 : var id = FCMySSComponent.getClientID(client);

其实很简单但是非常有意思,你说呢?

第三部分
现在来讲述getClientGlobalStorage和getClientLocalStorage方法。
在gFrameworkFC对象中并没有直接定义getClientGlobalStorage和getClientLocalStorage方法,只是定义了getClientGlobals方法。
1 : gFrameworkFC.getClientGlobals = function(client) {
2 : return this.clientGlobals[client.__ID__];
3 : }

getClientGlobalStorage和getClientLocalStorage方法就是在components对象中定义的
01 : FCComponent.prototype.getClientGlobalStorage = function( client ) {
02 : return gFrameworkFC.getClientGlobals(client);
03 : }
04 : FCComponent.prototype.getClientLocalStorage = function( client ) {
05 : if ( this.clientLocalStorage == null )
06 : this.clientLocalStorage = new Object();
07 : var cls = this.clientLocalStorage[client.__ID__];
08 : if ( cls == null )
09 : cls = this.clientLocalStorage[client.__ID__] = new Object();
10 : return cls;
11 : }

这两个方法非常有用,用来区分全局变量和组件实例变量。
这两个方法的调用参数是客户端对象(这个客户端对象具有一个唯一的__ID__)返回一个新的对象.
如果我们给getClientGlobalStorage设置了某个属性,就可以从任何地方访问到该属性值;但是我们如果给getClientLocalStorage对象设置属性值后,只能在该组件实例中访问该属性值,同时也是限制客户端(唯一的连接__ID__可以访问)。
那么如何才能从其它客户端对象访问 getClientGlobalStorage ?
我们只需要在调用对象的方法的时候包含 __ID__ 属性就可以,这个 __ID__ 属性值必须是唯一的。
当我们需要释放某个组件实例的变量可以用releaseLocalStorage方法
releaseLocalStorage方法在components 组件对象中定义
1 : FCComponent.prototype.releaseLocalStorage = function( client ) {
2 : if ( this.clientLocalStorage != null )
3 : delete this.clientLocalStorage[client.__ID__];
4 : }

使用的时候很简单:
1 : FCMySSComponent.releaseLocalStorage(Client);

建议在用户断开连接的时候释放存储,当然你可以保留对象,但是要记住每次新的客户端连接(甚至是之前的同一个用户)都会得到一个新的客户端 __ID__ 值,所以对象在以后将不会被再次使用。
1 : //我们通常在服务器端组件连接的时候会定义两个对象
2 : var cglobal = this.getClientGlobalStorage(client);
3 : var clocal = this.getClientLocalStorage(client);
4 :
5 : //在断开连接的时候会释放
6 : this.releaseLocalStorage(client);
FLASH COM学习笔记.23 发布和播放MP3
 
播放MP3文件
我们知道,Flash中默认的流式播放格式是Flv格式,但是在应用程序中,你可以通过客户端脚本来播放MP3音频文件和ID3信息,并使用服务器端脚本发布到stream流。
你需要上传MP3文件到服务器端的/streams/application_instance目录(Macromedia FCS MX 1.5 在录制视频流的时候会自动创建 streams 目录,如果不存在,你也可以手动创建)。例如你有个名为CDPlayerApp应用程序,你可以上传MP3文件到/applications/CDPlayerApp/streams/application_instance目录。
通过设定共享目录,你还可以在其它应用程序之间共享MP3。
找到Vhost.xml文件中的节点,在中添加需要共享的目录,如:
foo;c:\data
表示所有含有foo名称的目录都会被定向到c:\data目录,如foo/bar会被定向为c:\data\bar.flv。
详细的Vhost.xml说明可以参考FlashCom管理手册中相关部分。
然后,通过Stream.play指令指定播放的路径和想要播放的MP3文件。为了播放MP3文件,我们需要使用 NetStream对象的play方法,或者使用MC对象的attachAudio方法,特别需要注意的是,在播放文件前面要加上mp3播放标识前缀 mp3:,我们来看代码示例:
1 : //非共享方式播放
2 : vidObj.attachVideo(mystream);
3 : mystream.play( 'mp3:bolero' );
4 : //文件bolero.mp3在FCS服务器的 C:\mp3_files 目录下面
5 : //该目录在vhost.xml中被映射到虚拟目录 mp3dir
6 : movieObj.attachAudio(mystream2);
7 : mystream2.play( 'mp3:mp3dir/bolero' );


提示: 在使用 NetStream.play 方法的时候如果不指定视频或音频格式,会默认为FLV格式, 所以在播放MP3的时候,你必须指定格式播放。也就是说,flv:granada和granada都会播放文件granada.flv,但是mp3:bolero只会播放文件bolero.mp3。注意,这里播放的文件都在服务器端。

要播放MP3文件的ID3信息,必须使用播放前缀id3:并定义相应的回调函数来捕捉id3数据。例如,显示bolero.mp3文件的ID3 信息:
1 : //displays the ID3 tag of bolero.mp3
2 : mystream.play( 'id3:bolero' );
3 : //callback function to capture the ID3 data. Data will be displayed with
4 : //'info.' preceding the data from the tag, for example, info.songtitle.
5 : mystream.onId3 = function (info){
6 : for (i in info){
7 : trace(i + ':' + info[ i ]);
8 : }
9 : }


支持的MP3 ID3信息的版本
FlashCom server 1.5 支持UTF-8, UTF-16, and ISO-8859-1 格式的 1.0, 2.3和 2.4.版本的ID3信息,并且只支持文本数据,例如:歌曲名、作者、备注和录制时间等。

使用服务器端脚本
你还可以使用服务器端的Stream对象来播放MP3和获取MP3文件的长度,更详细的可以参考服务器端脚本参考中的Stream.play and Stream.length
要删除MP3文件可以使用Application.clearStreams方法,
下面来看一个例子,通过Stream.play方法来发布MP3:
01 : // Set up the server stream
02 : application.myStream = Stream.get( 'music' );
03 : if (application.myStream)
04 : {
05 : // Publish the MP3 file bolero.mp3 to the stream 'music'
06 : // Use the mp3: prefix in front of the stream name and specify 0 for the
07 : startTime parameter to indicate the server should play the recorded stream
08 : bolero.mp3
09 : application.myStream.play('mp3:bolero', 0, -1);
10 : }

使用 Stream.play 方法来捕获和播放 ID3 信息,请参考下面的代码示例:
01 : // Set up the server stream
02 : application.myStream = Stream.get( 'description' );
03 : application.myStream.onId3 = function(info)
04 : {
05 : for (i in info)
06 : {
07 : trace(i + ': ' + info[ i ]);
08 : }
09 : }
10 : if (application.myStream)
11 : {
12 : // Publish the ID3 text tag data of bolero.mp3 to a stream 'description'.
13 : // Use the id3: prefix in front of the stream name and specify 0 for the
14 : startTime parameter
15 : application.myStream.play( 'id3:bolero', 0, -1);
16 : }
 
FLASH COM学习笔记.24 服务器安全(一)
 
FlashCom Server的安全对于应用程序来说很重要,虽然还不致于和PHP、ASP服务器端的安全一样,毕竟目前服务器端的操作功能还有限。
我们知道,给服务器配置防火墙是较为常用的服务器端安全防范措施,而且也是行之有效的方法。我们会来分析FlashCom Server如何配合防火墙来进行安全保护。
默认的FlashCom服务端口是1935,这就意味着FCS服务器IP地址的1935端口必须设为开放状态,下面的图示表示了不同的连接情况。
450) {this.resized=true; this.width=450;}" border=0 resized="true">
图1 没有任何防火墙的远程直接连接
450) {this.resized=true; this.width=450;}" border=0 resized="true">
图2 防火墙没有开放1935端口的连接情况
450) {this.resized=true; this.width=450;}" border=0 resized="true">
图3 防火墙允许1935端口的连接情况

你还可以配置FlashCom Server接受1935以外的端口,这只需修改配置文件Adaptors.xml 中的 项,例如下面的配置可以允许FCS服务器接受来自1935, 8080, 443 和 80端口的RTMP访问。
  1. <HostPort>:1935808044380</HostPort>

如果同一服务器上有其它服务在运行,并使用了相同的端口,请不要配置这些端口。
FlashCom 的默认管理端口是1111,更改管理员端口是一个好的建议,如果不想这样,可以在配置文件Server.xml中修改项。
最常见的WEB服务端口是80HTTP端口和443HTTPS端口,8080一般用作HTTP服务的备用端口,最简单的1935端口的解决方法是设置FCS服务器接受80和443端口(假设没有其它占用),为了监听1935, 443和 80 端口,可以配置Adaptors.xml文件如下:
  1. <HostPort>:193544380</HostPort>

如果要指定某个IP的端口访问,可以用
  1. <HostPort>XXX.XXX.XXX.XXX:193544380</HostPort>

许多情况下,你可能要穿越多个防火墙甚至使用HTTP通道,但是这样仍然可以正常工作,因为NetConnection对象已经支持该特性。当你使用RTMP协议的时候没有指定端口号,Flash会尝试使用1935端口,如果失败则会尝试443端口,如果仍然不行,就使用80端口最后尝试。
看下面的连接代码:
1 : nc.connect( 'rtmp://host.domain.com/myApp/myInstance' );

为了更好的使用FlashCom服务和安全性考虑,有如下建议:
1. 在同一台FlashCom服务器上不要使用WEB服务
2. 如果需要请配置Web服务和FlashCom服务不同的IP地址
3. 配置你的Web服务只使用443或8080端口,80端口留给FlashCom

另外一个方案是配置FlashCom服务接受8080端口,连接方式修改为
1 : nc.connect( 'rtmp://host.domain.com:8080/myApp/myInstance' );

当指定了端口号后,Flash只会尝试指定的端口访问。

除了rtmp协议之外,FlashCom1.5和FlashPlayer 6,0,65,0之后还支持rtmpt协议
1 : nc.connect( 'rtmpt://host.domain.com/myApp/myInstance' );

使用rtmpt协议的时候,我们无须指定端口,Flash会使用80端口连接。其实我们无须使用rtmpt协议,因为默认的rtmp连接方式也会尝试该种方式的连接。
1 : nc.connect( 'rtmp://host.domain.com/myApp/myInstance' );

当我们使用上面的连接代码的时候,系统会自动按照下面的顺序使用端口和协议。

  1. 1 1935 RTMP 
  2. 2 443 RTMP 
  3. 3 80 RTMP 
  4. 4 80 RTMPT 
 
FLASH COM学习笔记.25 服务器安全 (二)
 
除了使用防火墙之外,很多企业为了使得网络更安全,还会使用代理服务器作为内部服务器和因特网之间的中介。
通过和防火墙整合,代理服务器可以防止客户机直接连接到因特网,所有访问请求都来自代理服务器,并且可以缓存页面内容和提升网络访问速度。这样通过代理服务器,防火墙就可以屏蔽所有来自客户端的直接请求,包括80端口,只有代理服务网可以通过80端口访问外部网络。
450) {this.resized=true; this.width=450;}" border=0>
图1 代理服务器和防火墙的配合使用

在Macromedia 的HTTP通道技术之前,在代理服务器之后的客户机是不能够连接FlashCom Server,但是现在仍然可以做到。从代理服务器的角度来看,使用RTMPT协议就如同使用HTTP请求一样,FlashCom Server端的回应也就像是HTTP回应一样。但是,代理服务器并不能保证请求成功,因为代理服务器会首先读取缓存。
每次成功的请求在服务器端都会有回应,大致的内容如下:
  1. HTTP/1.1 200 OK
  2. ServerNetscape-Enterprise/6.0
  3. DateSat24 May 2003 01:09:43 GMT
  4. Content-typetext/html
  5. Etag'c96066c3-1-0-1e8'
  6. Last-modifiedTue25 Jun 1996 19:11:18 GMT
  7. Content-length488
  8. Accept-rangesbytes


FlashCom Server返回的头信息不包含Content-type,也就会默认为text/html。
FlashCom Server升级为1.5版本之后,一个引人注目的地方就是重写了SimpleConnect组件的代码,当默认的1935端口无法连接时候,增加了额外的特性来加速连接。也就是说,如果我们在使用SimpleConnect组件连接的时候使用不带端口参数的RTMP协议,那么SimpleConnect组件会尝试下面的连接方式:
1. 创建一个NetConnection对象并使用默认的1935端口进行常规连接
2. 等待250ms后创建第二个NetConnection对象, 尝试使用RTMPT方式使用80端口进行连接
3. 接收第一个成功的连接,并关闭和删除另一个NetConnection对象
严格来说,这个不是必须的。事实上,FlashPlayer会依次尝试使用1935, 443和80端口的RTMP连接 ,然后再尝试使用80端口的RTMPT方式连接,但是这样很耗时间。如果在第一次RTMP连接后,启用80端口的RTMPT方式可以有效的加速连接过程。我们可以看下SimpleConnect组件中FCSimpleConnectClass类的actualConnect()方法就可以明白Macromedia是怎么处理的。当然,并不是每个人都使用SimpleConnect组件来开发,下面的代码可以给出一些提示和示例。
001 : // The onConnect function is called when a connection is made.
002 : function onConnect(nc){
003 : _global.main_nc = nc; // Assign the successful nc to a global variable.
004 : // For test purposes trace out the uri to see which protocol we are using
005 : trace( 'onConnect> ' + nc.uri);
006 : // Create a new onStatus handler for the successful NetConnection object:
007 : main_nc.onStatus = function(info){
008 : // your own onStatus handler code goes here
009 : // to handle errors and other events.
010 : // For testing this just prints out the contents of the information object.
011 : trace( '----main_nc.onStatus----' );
012 : for (var p in info){
013 : trace(p + ': ' + info[ p ])
014 : }
015 : }
016 : // Now connect other components and/or initialize your program.
017 : }
018 :
019 :
020 : // The onConnectFailed function is called if a connection cannot be made.
021 : function onConnectFailed(info){
022 : // Examine the info object and
023 : // report why you can't connect.
024 : // This code just traces out the information object.
025 : // Replace it with your own error handling.
026 : trace('----onConnectFailed----');
027 : // Loop through all the properties of the information object.
028 : for (var p in info){
029 : trace(p + ': ' + info[ p ]);
030 : // If the application rejects the connection and passes back
031 : // and application object loop through all its properties too.
032 : if (p == 'application'){
033 : var appObj = info.application;
034 : for (var q in appObj){
035 : trace('
' + q + ': ' + appObj[q]);
036 : }
037 : }
038 : }
039 : }
040 :
041 : // Create a new NetConnection object that will be used to
042 : // attempt an RTMP connection.
043 : rtmp_nc = new NetConnection();
044 : // Create an onStatus handler that will dispose of the rtmpt_nc
045 : // NetConnection object if this connection succeeds first.
046 : rtmp_nc.onStatus = function(info) {
047 : this.pending = false;
048 : if (info.code == 'NetConnection.Connect.Success') {
049 : if (rtmpt_nc.pending) {
050 : rtmpt_nc.onStatus = null;
051 : rtmpt_nc.close();
052 : rtmpt_nc = null;
053 : clearInterval(connectionID);
054 : }
055 : onConnect(this);
056 : } else
057 : if (! rtmpt_nc.pending){
058 : onConnectFailed(info);
059 : }
060 : }
061 :
062 : // Create a new NetConnection object that will be used to
063 : // attempt an RTMPT connection.
064 : rtmpt_nc = new NetConnection();
065 : // Create an onStatus handler that will dispose of the rtmp_nc
066 : // NetConnection object if this connection succeeds.
067 : rtmpt_nc.onStatus = function(info) {
068 : this.pending = false;
069 : if (info.code == 'NetConnection.Connect.Success') {
070 : if (rtmp_nc.pending) {
071 : rtmp_nc.onStatus = null;
072 : rtmp_nc.close();
073 : rtmp_nc = null;
074 : }
075 : onConnect(this);
076 : } else
077 : if (! rtmp_nc.pending){
078 : onConnectFailed(info);
079 : }
080 : }
081 :
082 : // Mark both nc objects as pending.
083 : rtmp_nc.pending = true;
084 : rtmpt_nc.pending = true;
085 :
086 : // Try to connect with rtmp right away:
087 : rtmp_nc.connect('rtmp://host.domain.com/myApp/myInstance', userName, password);
088 :
089 : // Setup an interval to try rtmpt in 400 milliseconds:
090 : connectionID = setInterval(connectRTMPT, 400);
091 :
092 : // Clear the interval and try to connect with RTMPT when this function is called.
093 : function connectRTMPT(){
094 : clearInterval(connectionID);
095 : rtmpt_nc.connect('rtmpt://host.domain.com/myApp/myInstance', userName, password);
096 : }
097 : //You can modify this code to try other ports. For example, if you can't use port 80 and want to try port 8080, use this code:
098 : function connectRTMPT(){
099 : clearInterval(connectionID);
100 : rtmpt_nc.connect('rtmpt://myHost.myDomain.com:8080/myApp/myInstance', userName, password);
101 : }
 
FLASH COM学习笔记.26 服务器安全(三)
 
服务器加密传输
在浏览器中运行Flash的时候,macromedia通过RTMPT方式使用HTTP服务来交互数据。自从浏览器支持SSL方式后,一个更安全的加密HTTPS通道也随之而来了。你可以使用RTMPS方式来连接:
1 : nc.connect('rtmps://myHost.myDomain.com/myApp/myInstance');

当你指定RTMPS作为连接方式时,系统默认使用443端口进行连接。但是FlashCom MX Server1.5并不支持SSL,所以要使用SSL方式加密交互数据并不可能,所以我们需要使用其它的方式来实现,大致有三种方法:
1. 使用第三方的加密传输软件(如stunnel, http://www.stunnel.org/),用来监控443端口,并在1935和443端口之间来回传输未经加密的数据。
450) {this.resized=true; this.width=450;}" border=0>

2. Flash文件直接连接到另外一台安装有stunnel的服务器,并且配置第二台服务器连接FlashCom Server,其间传输未经加密的数据。这种方式,安装有stunnel的服务器充当了中间层服务器。
450) {this.resized=true; this.width=450;}" border=0 resized="true">
需要注意的是:stunnel监听443端口的加密数据,然后通过1935端口传输未经加密的数据给另一台FlashCom Server。在这种方式下,Flash连接的服务器必须是stunnel,而不是连接到flashCom Server,例如,假如stunnel服务器的域名是stunnel.mydomain.com,那么正确的连接代码应该写成:
  1. rtmps://stunnel.mydomain.com/myapp/myinstance


3. 在网络中使用专门的SSL加速器(通常使用交换机来完成),来接收加密数据并解密后传输给FlashCom Server。
450) {this.resized=true; this.width=450;}" border=0 resized="true">

在以上三种方法中,第三种方法到目前为止应该说是最好的解决方法,虽然花费昂贵一些。专门的网络SSL硬体解决比服务器端的安装配置要来的简便和高效。
SSL硬件加速器通过网络交换机工作,不需要在WEB 服务器上加载SSL进程,配置stunnel服务更是一个挑战性的工作。

PS:其它关于FlashCom安全方面的文章
1. a security checklist for Macromedia Flash Communication Server MX.
2. Macromedia Flash Communications Server MX security overview
3. Updates to the SimpleConnect component
4. Securing Macromedia Flash Communication Server
 
FLASH COM学习笔记.27 服务器安全问答
 
什么是FlashCom Server?


(略)


什么是FlashCom应用程序


也就是一个和Flash Communication Server交流的Flash应用程序,可以是一对一,也可以是一对多,甚至多对多的模式,还可以用作智能化的机器人交流,例如进行实时的数据传送和通知。
一个典型的FlashCom应用程序包含:
1 : 应用程序入口:网页或独立应用程序,通常包含一些SWF文件
2 : 客户端swf文件:可以是网页或独立应用程序形式,一般包含了FlashCom应用程序的UI,也包含程序执行的一些客户端脚本
3 : 服务器端代码和数据:服务器端的脚本
4 : 应用程序服务器:包含其它PHP、ASP或CFML脚本的服务器


FlashCom使用的网络协议是什么


Flash使用RTMP(the Real-time Messaging Protocol )协议作为客户端和服务器端的传输协议,这是一个专门为高效传输视频、音频和数据而设计的TCP/IP 协议,使用RTMP协议传输的数据是未经加密的,包括用户名和密码等认证信息。
虽然RTMP协议不安全,但是也可以通过使用支持SSL的服务器来实现安全传输。

有哪些方式控制用户访问


FCS支持多种方式的用户连接认证。
1. 无须用户名和密码的访问(不推荐)
2. 基本认证:通常使用用户名和密码,经由RTMP方式传输,在服务器端验证
3. 入场券认证:客户端通过入场券交由服务器端认证,并且只能在一段时间之内使用。
4. IP认证:在服务器端配置允许访问IP或域名

如何控制连接用户数


在服务器端可以使用脚本统计目前连接用户数,并可以拒绝超过用户数之外的连接。

如何保存用户数据隐私


用户数据以共享对象的方式保存,可以保存在用户端和服务器端,可以是临时的也可以是永久的。应用程序只能访问自己相关的共享对象,但是共享对象的存储使用未经加密的二进制文件,其中有些安全方面的隐患。

如何控制对主机资源的使用


应用程序之间不能够相互访问文件或其它资源,每个应用程序使用唯一的目录。管理员可以设置每个应用程序的带宽和使用磁盘空间,可以防止某个应用程序的资源消耗过大。

网络适配器、虚拟主机和应用程序的关系


FCS支持多个网络适配器,除此之外,还可以给每个适配器配置多个虚拟主机目录,每个虚拟目录又可以运行应用程序实例。例如,相同的视频聊天应用程序的不同实例之间是不能交互数据的,应用程序总是运行在同一个虚拟主机上。

如何配置服务器端


合适的服务器配置是保障应用程序安全的关键,下面一些地方是管理员可以配置的,也是和安全相关的:
01 : 管理员帐号和密码
02 : 允许或禁止的IP地址或域名
03 : 性能优化的参数设置
04 : 连接访问的IP和侦听端口
05 : 服务器访问和应用程序事件日志
06 : 服务器端脚本的优化
07 : 应用程序的带宽性能
08 : 客户端连接到应用程序的带宽占用
09 : 用于视频、数据和应用程序存储的目录
10 : 应用程序实例、视频流和共享对象的限制


合理的FlashCom服务器端和客户端应用程序的开发和配置能够使得应用程序更安全,更详细的安全建议请参考其它相关文章。
    FLASH COM学习笔记.28 服务器安全建议
    把FlashCom开发和配置方面的安全建议作个总结:
    01 : 使用安全的管理员帐号和密码设定,不要使用admin和administrator之类的用户名,密码最好包含数字和字符,长度不要少于8位;
    02 : 在Server.xml文件中配置标记,限制可以连接管理应用程序的客户端;
    03 : 更改默认的管理控制台端口,并配置防火墙阻止访问;
    04 : 在Vhost.xml文件中配置标记,限制可以连接该虚拟主机的客户端;
    05 : 如果你的应用程序没有创建或使用视频流,设置Vhost.xml中的标记值为0;
    06 : 根据你的要求设置Vhost.xml中的标记为on或off;
    07 : 如果需要更改内存分配、垃圾回收频率或其它相关设置的时候,检查Server.xml文件中的标记;
    08 : 如果你的应用程序连接了多个服务器,请确认设置了Server.xml文件中的标记;
    09 : 反复检查Vhost.xml文件中的标记,确保你没有侦听多余的端口,并确认防火墙正常启用或屏蔽了这些端口;
    10 : 在Adaptor.xml 文件中配置标记,限制可以连接到应用程序的域名和IP地址;
    11 : 最终发布的客户端程序不要显示出应用程序名称以及服务器地址等信息,最好是硬编码在源文件中(虽然还是不安全);
    12 : 始终在服务器端验证客户端连接的提交地址是否合格,这样可以防止使用自己的客户端程序来连接相同的应用程序;
    13 : 在你的Flash文件中添加基本的握手代码,防止客户端有欺诈行为,因为Flash数据传输没有加密;
    14 : 检查服务器端脚本移除所有调试代码或其它不需要的代码;
    15 : 移除所有的不再使用的外部或旧版脚本;
    16 : 在Vhost.xml中设置标记指明应用程序的位置,这个路径应该不能通过WEB方式或其它方式访问;
    17 : 删除不必要的应用程序;
    18 : 删除安装Macromedia Flash Communication Server MX后自带的应用程序范例;
    19 : 设置Vhost.xml文件的标记指明视频流文件的存储路径,这个路径应该不能通过WEB方式或其它方式访问;
    20 : 设置Vhost.xml文件的标记允许合适数量的共享对象,其中有些参数值会受服务器授权的限制;
    21 : 设置Vhost.xml文件的属性来限制对虚拟主机的连接;
    22 : 在Application.xml文件中的段标记中更改属性防止应用程序死循环;
    23 : 检查Application.xml中的所有属性;
    24 : 所有的web文件(HTML, SWF等)应该放置到你的web服务器目录,如果同一台服务器也是FlashCom服务器的话,要确保分开;
    25 : 删除你的web目录下面的所有相关应用程序文件或资源(尤其是fla文件);
     
    FLASH COM学习笔记.29 服务器日志
     
    在管理FlashCom MX Server的时候,一件非常重要的事情就是收集运行在服务器上的不同应用程序以及应用程序实例的状态信息。在大多数的服务器环境中,服务器日志对于管理和故障检查来说是非常有用的工具。
    FlashCom Server在同一时间可能同时运行着多个应用程序以及应用程序实例,我们需要了解多少用户连接和各个应用程序或应用程序实例消耗了多少带宽。服务器管理API提供了灵活的方法可以收集这些信息。我们来了解下不同的服务器日志记录方法和FlashCom服务器管理API提供的示例日志程序,这些日志程序和管理控制台应用程序类似。
    一、日志类型
    1. <strong><span style="color: orange\">1. 服务器访问日志</span></strong>:服务器把所有的访问日志记录在名为access.flv的流文件中,我们可以通过Vhost.xml中的<RecordAccessLog>标记项来控制是否记录,如果设置为true,服务器就会保存访问信息到access.flv文件中,该文件一般位于应用程序目录的admin/streams/logs 目录下。

    1. <strong><span style="color: orange\">2. 应用程序调试日志</span></strong>:服务器端脚本经常会使用tracer命令来调试应用程序,我们可以通过Applications.xml中的<RecordAppLog>标记项来控制是否记录该调试信息,如果设置为True,服务器会保存调试信息到admin/streams/logs/application/YourAppName/目录下面并且使用和应用程序实例名相同的文件名。

    1. <strong><span style="color: orange\">3. 服务器端脚本日志</span></strong>:服务器管理应用程序是一个特殊的应用程序,允许控制和访问服务器的相关信息。服务器端脚本可以访问这些数据并保存下来以便以后恢复。

    不管有多少日志信息存储在服务器上,它有可能必须被恢复,我们需要分析和格式化成日志信息供以后使用。例如,可以通过一个特殊的客户端swf文件来访问这些日志,下载日志信息和创建报告。
    有两个范例日志程序:Flash Communication Server Log Reader和Flash Communication Server Bandwidth Monitor (Flogger)

    二、 Flash Communication Server Log Reader
    该应用程序用于读取FlashCom Server日志记录。允许管理员收集服务器端的使用报告,也可以定制服务器端日志记录情况。使用之前,你最好熟悉FlashCom Server的安装、配置和管理。
    [ 下载 ]

    三、 Flash Communication Server Bandwidth Monitor (Flogger)
    该应用程序用于监视服务器带宽使用情况。
    [ 下载 ]
     
    FLASH COM学习笔记.30 服务器端ActionScript的命名和搜索路径
     
    翻译自官方的FlashCom TechNote 译者:liu21st(晴天的鱼)
    原文出处:mm/serverside_names.htm

    当FlashCom Server端应用程序加载的时候,服务器会检查服务器端的ActionScript文件。
    该文件可以位于application目录下或者其scripts子目录下,并且可以有多种命名方式。
    通常,都放在application目录的应用程序目录下面,名称为main.asc。这是FlashCom Server默认的方式,但是,为了安全和管理起见,我们应该另外命名以更好的区分不同的应用程序。因此,使用<application_name>.asc的命名是一个良好的习惯,我们甚至可以使用js作为文件扩展名。
    下面是服务器端Actionscript文件的搜索顺序:
    1 : 位于/scripts目录下面的main.asc文件
    2 : 位于目录下面的main.asc文件
    3 : 位于/scripts目录下面的main.js文件
    4 : 位于目录下面的main.js文件
    5 : 位于/scripts目录下面的.asc文件
    6 : 位于目录下面的.asc文件
    7 : 位于/scripts目录下面的.js文件
    8 : 位于目录下面的.js文件

    在上面的搜索路径中,<appName>是指应用程序的目录名称
    一般地,对于开发模式,该目录位置在C:\inetpub\wwwroot\flashcom\applications\<appName>
    对于产品模式 默认位置为 C:\Program Files\Macromedia\Flash Communication Server\flashcom\applications\<appName>.
    如果是Linux环境,应该是/opt/macromedia/fcs/application/<appName>
    加载另外的Actionscript文件
    如果要在服务器端ActionScript文件中加载另外的文件,需要使用Load命令
    如load( 'logic.asc' );
    FlashCom server 首先会在当前目录搜索logic.asc文件,然后再搜索 Application.xml (位于C:\Program Files\Macromedia\Flash Communication Server MX\conf\_defaultRoot_\_defaultVHost_\Application.xml或/opt/macromedia/fcs/conf/Application.xml)中<ScriptLibPath>标记指定的目录。
    对于开发模式,该标记默认为
    1 :

    如果要指定多个搜索路径,可以用分号隔开
     
    FLASH COM学习笔记.31 服务器集群和负载均衡
     
    本篇主要讲述在进行FCS开发过程中如何使用多个视频服务器来做集群服务和负载均衡处理。
    在FCS的应用过程中,带宽消耗是一个很严重也是很现实的问题,好的解决方法就使用多个服务器进行负载均衡,也就是说使用服务器集群技术。
    有三种服务器集群的方案:
    1 使用专门的主服务器来连接多个子服务器
    450) {this.resized=true; this.width=450;}" border=0>
    2 每台服务器既可以作为主服务器也可以充当子服务器
    450) {this.resized=true; this.width=450;}" border=0>
    3 每台服务器都作为主服务器
    450) {this.resized=true; this.width=450;}" border=0>

    那么到底哪种方式最好呢?这取决与你所做的应用,每种方式都可以满足各自不同的需要。
    根据FCS应用程序的架构和流媒体的特性,为了最低限度的减少数据丢失以及数据同步问题,第三种方案不失为一种好的方案。
    举个例子,假如你有个应用程序同时有1000在线用户需要连接FCS服务,而你每台服务器的带宽仅仅能够满足500个用户的需求,或许你会说为什么不用单独一台服务器来作负载均衡控制,答案很简单:多余。况且让我们设想一下,如果哪天这台服务器想要休息一下,那么你的应用会怎么样?
    因此,为了安全起见,使用多个主服务器的方式最适合,至少不会发生上面所说的问题。
    集群方式确定了,那么在开发过程中如何使用呢?
    也有两种方式,取决你所做的应用:
    1、在不同服务器之间同步
    2、不同服务器之间不进行同步(严格的说不能说是集群技术)
    其实两种方式的差异不用说也知道,但如果只是想减轻带宽负荷,并不想在多个服务器之间保持数据一致就可以采用第二种方式。
    关于第一种方式,Jake Hilton给出了比较好的解决方式,在此也不多说,简单说明下。原理就是在进行服务器连接、发布和设置操作的时候循环对每个在线的服务器进行操作。
    例如:
    1. //serverArray 是连接服务器数组
    2. for(var i in serverArray){ 
    3. this['nc'+i] = new NetConnection();
    4. this['nc'+i].connect(serverArrayIn[i]);
    5. this['nc'+i].onStatus = function(objIn){ _self.ncStatus(objIn) };
    6. liveServers.push(i);
    7.  }

    在onStatus方法中会检查在线服务器,调用pingBack方法得到liveServers的值。
    在应用程序的Main.asc文件中添加如下代码:
       
    1. Client.prototype.serverPing=function(srvId){ 
       
    2.   return { 'serverId':srvId,'serverName':application.hostname };
       
    3.  }
       
    4. Client.prototype.setSoObject=function(soName){ 
       
    5.   setUpSharedObject(soName);
       
    6.  }
       
    7. Client.prototype.getSoValue=function(soName,propName){ 
       
    8.   return eval(soName).getProperty(propName);
       
    9.  }
    10. Client.prototype.setSoValue=function(){  //soName,propName,propVal
    11.   eval(arguments[0]).setProperty(arguments[1],arguments[2]);
    12.  }
    13. function setUpSharedObject (soName) { 
    14.   if(!this[soName]){ 
    15.     trace('setting up shared object '+soName);
    16.     this[soName]=SharedObject.get(soName,true);
    17.    }
    18.  }
    把Main.asc文件放到你的FCS应用程序目录下面后重启应用。

    客户端测试代码示例:
       
    1. import com.sitename.MultiConnection
       
    2. mc = new  MultiConnection();
       
    3. mc.connect(['rtmp://server1.com/test','rtmp://server2.com/test']);
       
    4. mc.onStatus = function(objIn){ 
       
    5.   trace(objIn.code);
       
    6.   if(objIn.code == 'NetConnection.Setup.Success'){ 
       
    7.     mc.sharedObjectSetup ('info_so',true);
       
    8.     mc.setNetStreams();
       
    9.     myMic Microphone.get();
    10.     mc.attachAudio(myMic);
    11.     mc.nsStatus=function(objIn){ 
    12.       trace(objIn.code);
    13.      }
    14.     mc.publish ('webCastName','live');
    15.    }
    16.  }
    17. mc.info_so_sync = function(){ 
    18.   trace('so synced');
    19.  }

    代码连接多个服务器,并且在每个服务器上创建共享对象info_so,并且通过info_so_sync 方法来同步。
    下载 完整的类和示例程序

    第二种方法就更简单了,把实现思路说明一下。
    在客户端判断不同的聊天室或者不同的用户ID,转向不同的FCS服务器。服务器端代码不需要任何修改,客户端只需做一个引导程序
     
    Flash Media Server学习日记 一
     
    终于知道怎么做流式播放了...

    不知道是我问的问题太低级还是没表达清楚,走了N个论坛都没人回帖子.

    后来实在没办法了,只能用GOOGLE翻译国外的页面慢慢研究了...

    经过俩小时的搜索查看,没白搞.终于理出FLASH MEDIA SERVER的目录结构了...

    我的FLASH MEDIA SERVER安装在D盘.

    D:\Program Files\Macromedia\Flash Media Server 2\

    打开FMS的目录,进到applications目录,新建一个名叫Tensharp的目录.(就是我的测试站点,嘿嘿.)

    然后在Tensharp里新建个名字叫Streams的目录,再在Streams里建个_definst_目录.

    FLV文件就放在这里...在FLASH里读的路径是 rtmp:/tensharp/life(注意,这里没FLV文件的后缀名.)

    打开FLASH,新建一个文档.

    新建一个视频对象取名为MyVideo

    在第一桢上按F9,输入:

     

    var MyNetConnection = new NetConnection ();
    MyNetConnection.connect ("rtmp:/tensharp");
    MyNetConnection.onStatus = function (TeN) {
     if (TeN.code == "NetConnection.Connect.Success") {
      trace ("服务器开放中...");
     }
    };
    var MyNetStream = new NetStream (MyNetConnection);
    MyVideo.attachVideo (MyNetStream);
    MyNetStream.setBufferTime (5);
    MyNetStream.play ("life");

    先前做完那个东西感觉FMS并不是很难..比当时第一次用FLASH + XML做东西

    容易了许多..可能是还没找到套路吧.

    而且FMS的书在国内实在太难买了(中文版

     

Copyright © 2024 Zcr
Powered by .NET 8.0 on Kubernetes