与服务端通信 第四节   与Flash Media Server交互
        Flash Media Server 简称 FMS,目前版本号已经是3.5,FMS 可以作为提供诸如视频会议,网络游戏等交互式应用的服务平台,尤其在多媒体方面表现

尤为出色,Adobe提供了免费的开发版供大家学习,开发版支持10个客户端。本节内容就是教会大家如何使用 FMS 制作一个简单的聊天室。

学习目标

这一节要教会大家使用 FMS 通过SharedObject方式来实现聊天室的功能,先来看看完成后的作品。 (图一百零九)

 

图一百零九

学习目标

工作原理

本例中 FMS 聊天室的工作原理很简单,关键在于一个名为SharedObject的对象,我们可以把它看成所有聊天用户共享的全局对象,谁都可以读写它,如果A

用户发言就等于把一条对话追加到这全局变量中去,这个变量一旦发生改变便会通知所有其他在线聊天用户说:“同志们我的内容被更新啦”,其它客户便

可以去从这个变量 中取得最新的聊天记录,从而知道刚才A说了什么。稍微有点复杂,看一遍没看懂的同学,请认真地逐字逐句的把前面这段话好好理解,

这是聊天室现原理所在。

准备工作

1、下载工具

FMS :FMS 3.5(需要注册一个Adobe的账号)  Servlet 容器:Tomcat 6.0  

2、安装 FMS 3.5。

遇到下图这一步,是让你输入序列号,当然我们肯定没有,所以空着直接 Next。不输入序列号我们的 FMS就会成为开发版可以永久使用,但是最多只能支持10个客户端。(图一百一十)

 

File:Flash_Builder_4_5Z_4J_fms_image001.png

之后会让你选择安装 Apache 服务器,由于我们在前几节课程中都是使用的 Tomcat,因此这一步就不安装了。 (图一百一十一)

File:Flash_Builder_4_5Z_4J_fms_image003.png

图一百一十一

安装FMS 3.5

       再接下去就是要配置 FMS 的管理员账号了。 (图一百一十二)

File:Flash_Builder_4_5Z_4J_fms_image005.png

图一百一十二

安装FMS 配置账号

图一百一十

安装FMS 3.5

最后是配置 FMS Server 的端口以及 Server 控制台的访问端口,系统默认是 1935,80,1111这3个端口,请确保没有被其它程序占用。(图一百一十三)

File:Flash_Builder_4_5Z_4J_fms_image007.png

图一百一十三

安装FMS 配置端口

3、在 FMS 安装目录下的“applications”文件夹下建立一个名为“myApp”的文件夹,作为 Server 端项目根路径。以后我们的 SharedObject 对象便会

存放在这个位置。(图一百一十四)

File:Flash_Builder_4_5Z_4J_fms_image009.png

图一百一十四

建立myApp文件夹

4、在开始菜单中可以看见一些按钮,蓝色部分是打开服务器控制台,红色部分是关闭 FMS 服务,绿色部分是打开 FMS 服务。

File:Flash_Builder_4_5Z_4J_fms_image019.png

点击蓝色部分按钮输入之前设置的账号可进入控制台。

File:Flash_Builder_4_5Z_4J_fms_image021.png

实现步骤

1、建立 Flex 项目,因为我们做的是聊天室,这个工程架设在 Web 容器中(如 Tomcat 等)中会更加便于我们调试,所以我们在服务器技术里选择“J2EE”,由于这里服务端技术使用的是 fms,因此我们将“使用远程对象访问服务”给勾去后点击“下一步”。(图一百一十七)

File:Flash_Builder_4_5Z_4J_fms_image011.png

2、之后我们对项目进行服务器配置。

File:Flash_Builder_4_5Z_4J_fms_image013.png

一百一十八

服务器配置

一百一十七

建立FLEX项目

3、绘制简单的聊天界面,一个 TextArea 用于显示对话,一个 TextInput 用于输入用户昵称,一个 TextInput 用于输入消息,一个 Button 按钮发送对话。 (图一百一十九)

File:Flash_Builder_4_5Z_4J_fms_image015.png

一百一十九

绘制界面

设置完后我们顺便为这些控件设置下标示。“textAreaContent”,“textInputName”,“textInputMessage”,“buttonSend”等。

4、我们定一个 Message Bean 来记录每一条对话。结构如下,分别是昵称,消息内容,时间。

package cn.airia.fb4.vo
{ 
    public class Message
    {
        public function Message()
        {
        } 
        public var nickname:String;
        public var msg:String;
        public var time:Date;
    }
}

5、接下去开始编码,首先我们定义一些变量。

private var netConnection:NetConnection;
private var serverApp:String = "rtmp://192.168.1.101/myApp";

private var talkSO:SharedObject;

netConnection:可以认为它是 Flex 与 FMS 通讯的桥梁。  




serverApp:配置的是 FMS 服务的地址,注意这里使用的是rtmp协议。 




talkSO:一个SharedObject对象,可以把它看成一个供所有聊天室用户存放聊天记录的全局对象。  

6、在程序初始化执行一些操作。

private function init():void
{ 
    netConnection = new NetConnection();
    buttonSend.addEventListener(MouseEvent.CLICK,sendMessage);
    netConnection.addEventListener(NetStatusEvent.NET_STATUS,netStatusHandler);
    netConnection.addEventListener(AsyncErrorEvent.ASYNC_ERROR,asyncErrorHandler);
    netConnection.connect(serverApp);

}

NetStatusEvent.NET_STATUS:用于监听连接状态。 




AsyncErrorEvent.ASYNC_ERROR:是用于监听一些连接中的错误信息。  




netConnection.connect(serverApp):这句的作用是正式开始连接 FMS 服务器。  

这里主要是加一些监听。

NetStatusEvent.NET_STATUS的回调函数netStatusHandler用于根据服务器返回状态判断是否连接成功。

private function netStatusHandler(evt:NetStatusEvent):void
{ 
    if(evt.info.code == "NetConnection.Connect.Success")
    {
        talkSO = SharedObject.getRemote("talk",netConnection.uri,false);
        talkSO.addEventListener(SyncEvent.SYNC,talkSOHandler);
        talkSO.addEventListener(AsyncErrorEvent.ASYNC_ERROR,asyncErrorHandler);
        talkSO.connect(netConnection);
    }
    else
    {
        Alert.show("connect failed "+evt.info.code);
    }

}

我们可以看到当服务器返回的 code 为“NetConnection.Connect.Success”时表示连接成功,那么我们就可以开始对这个全局共享变量talkSO

进行一些操作了。

SharedObject.getRemote("talk",netConnection.uri,false);这句的意思是,跑到 FMS 服务器下找“talk”这个文件,如果没有则新建一个用以存放

我们的全局变量,另外第三个参数的false的意思,就是说这个文件是临时的,当 FMS 服务器关闭时这个“talk”就被删除了。

小测试1:思考以下2个问题,如果回答不出,请重新阅读或放弃本教程。

netConnection.uri的内容及作用是什么?  




第三个参数如果是 true 是代表什么?  

talkSO.addEventListener(SyncEvent.SYNC,talkSOHandler);这句的作用比较关键,它监听的是talkSO变量也就是“talk”文件的内容有没有被其它用户

改写。

talkSO.connect(netConnection);这句例行公事,把前面对于 talkSO 的设置通过桥梁 netConnection 与 FMS 服务器扯上关系,大家死记硬背即可。

小测试2:思考以下2个问题,如果回答不出,请重新阅读或放弃本教程。

talkSO.addEventListener(AsyncErrorEvent.ASYNC_ERROR,asyncErrorHandler); 



这句意思是什么?  

7、桥梁,全局变量什么的都设置好了,接下去就是核心代码了。

private function sendMessage(evt:MouseEvent):void
{ 
    var array:ArrayCollection = new ArrayCollection();
    if(talkSO.data.msgList != null)
    {
        convertArrayCollection(array,talkSO.data.msgList as ArrayCollection);
    }
    var message:Message = new Message();
    message.nickname = textInputName.text;
    message.msg = textInputMessage.text;
    message.time = new Date();
    array.addItem(message);
    talkSO.setProperty("msgList",array);
    textInputMessage.text = "";

}

“talkSO”有个data属性,是用来存放数据的,我们需要它来存放我们所有的聊天记录,这里给聊天记录的集合起个名字叫做“msgList”,这段代码

的作用就是把“msgList”拿下来,然后把用户的发言追加进去,然后通过talkSO.setProperty("msgList",array);这句把它写回 FMS 服务器去。

private function talkSOHandler(evt:SyncEvent):void
{ 
    textAreaContent.text = "";
    if(talkSO.data.msgList != null)
    {
        var tmp:ArrayCollection = new ArrayCollection();
        convertArrayCollection(tmp,talkSO.data.msgList as ArrayCollection);                                 
        var formatter:DateFormatter = new DateFormatter();
        formatter.formatString = "HH:NN:SS";
        for(var i:int = 0;i<tmp.length;i++)
        {
            var message:Object = tmp.getItemAt(i) as Object;                                      
            var timeString:String = formatter.format(message.time);
            var fullMsg:String = message.nickname + " at " + timeString + " said:" + message.msg;
            textAreaContent.text = textAreaContent.text+fullMsg+"\n";
        }
    }

}

这段代码是对于“SyncEvent.SYNC”事件所作出的响应,当有用户更新了聊天记录时候就会触发执行。主要功能就是把聊天记录“msgList”从服务器

拿下来,然后遍历下所有对话,把它们打印在 TextArea 中。

private function convertArrayCollection(arrNew:ArrayCollection,arrOld:ArrayCollection):void
{ 
    arrNew.removeAll();
    for(var i:int = 0;i<arrOld.length;i++)
    {
        arrNew.addItemAt(arrOld.getItemAt(i),i);
    }

}

这段代码作用是用于 ArrayCollection 的复制。

8、运行代码,叫上你局域网的朋友一起测试吧,你也可以自己开2个浏览器进行测试。当有客户端连接上,你跑去 FMS 的控制台可以看到一些连接信息。

File:Flash_Builder_4_5Z_4J_fms_image023.png

总结:

      这节我们学习了在 FMS 中利用 SharedObject 方式实现了简单聊天室,目的在于让各位同学了解 FMS 的工作机制,包括今后你们在实现视频会议的时候, 其实其中原理也是一样的。本人在以往 Flex3 的开发中发现 SharedObject 的性能和可靠性实在不敢恭维( Flex4 中尚未验证),因此请大家在实际项目 中慎用 SharedObject 进行频繁的读写操作。

思考:

使用 FMS 实现简单的视频录制和播放。 使用 FMS 实现简单的多人视频。