Flex与.NET互操作(十二):FluorineFx.Net的及时通信应用(Remote Shared Objects)(三)

FluorineFx所提供的远程共享对象(Remote Shared Objects)和FMS的共享对象的功能是一样,对于熟悉FMS开发的朋友来说,学习FluorineFx的远程共享对象是非常简单的。

共享对象可以在服务器端创建,也可以在客户端创建。在客户端创建共享对象的方法和使用FMS开发是一样的,创建一个 NetConnection对象,通过该对象的connect()方法连接到服务器,然后通过SharedObject.getRemote()方法就可以在客户端创建一个远程共享对象。如下实例代码:

private function connectionServer():void
{
    var nc:NetConnection = new NetConnection();
    nc.connect("rtmp://localhost:1617/SOAPP","username","password")
    nc.addEventListener(NetStatusEvent.NET_STATUS,onStatusHandler);
    nc.client = this;
}

private function onStatusHandler(event:NetStatusEvent):void
{
    if(event.info.code == "NetConnectin.Connect.Success")
    {
        createSharedObject();
    }
}

private function createSharedObject():void
{
    var so:SharedObject = SharedObject.getRemote("OnLineUsers",nc.uri,false);
    so.addEventListener(SyncEvent.SYNC,onSyncHandler);
    so.connect(this.nc);
    so.client = this;
}

private function onSyncHandler(event:SyncEvent):void
{
  //..do other
}

在FluorineFx的服务器端创建远程共享对象和FMS有很大的区别,FluorineFx的 ISharedObjectService接口提供了专门用于创建远程共享对象的方法 CreateSharedObject(),ApplicationAdapter实现了此接口方法。定义如下:

public bool CreateSharedObject(IScope scope, string name, bool persistent)
{
      ISharedObjectService service = (ISharedObjectService)ScopeUtils.GetScopeService(scope, typeof(ISharedObjectService));
      return service.CreateSharedObject(scope, name, persistent);
}

如果要在服务器端创建远程共享对象,直接调用ApplicationAdapter类中的CreateSharedObject()方法就可以。如下在FluorineFx服务器端创建远程共享对象的代码块:

ISharedObject users_so = GetSharedObject(connection.Scope, "OnLineUsers");
if (users_so == null)
{
       //创建共享对象
        CreateSharedObject(connection.Scope, "OnLineUsers", false);
        users_so = GetSharedObject(connection.Scope, "OnLineUsers");
}

要想更新共享对象里的数据客户端还是使用setProperty()方法,而FluorineFx的服务器更新共享对象的方法则与 FMS不一样,使用的是FluorineFx.Messaging.Api.IAttributeStore接口提供的SetAttribute()和 RemoveAttribute()方法来更新共享对象里的数据。

陆续介绍了这么多,下面通过一个案例来看看该这么去应用远程共享对象。比如做IM、视频聊天、视频会议等及时通信类型的应用中,用户上线下线的频率非常高,这时候我们就可以使用远程共享对象去做在线用户的数据同步。

首先建立FluorineFx服务库,并建立一个应用类继承于ApplicationAdapter,通过重写ApplicationAdapter的相关方法来实现应用程序的不同需求,详细如下代码块:

using System;
using System.Collections.Generic;
using System.Text;
using FluorineFx.Messaging.Adapter;
using FluorineFx;
using FluorineFx.Messaging.Api;
using System.Diagnostics;
using FluorineFx.Messaging.Api.SO;
using FluorineFx.Exceptions;
using FluorineFx.Context;
using FluorineFx.Messaging.Api.Service;
using System.Collections;
using Fx.Adapter.DTO;

namespace Fx.Adapter
{
    /// <summary>
    /// 自定义ApplicationAdapter
    /// </summary>
    [RemotingService]
    public class MyApp : ApplicationAdapter
    {
        /// <summary>
        /// 应用程序启动
        /// </summary>
        /// <param name="application"></param>
        /// <returns></returns>
        public override bool AppStart(IScope application)
        {
            Trace.WriteLine("应用程序启动");
            return true;
        }

/// <summary>
        /// 房间启动
        /// </summary>
        /// <param name="room"></param>
        /// <returns></returns>
        public override bool RoomStart(IScope room)
        {
            Trace.WriteLine("房间启动");
            if (!base.RoomStart(room))
                return false;
            return true;
        }

/// <summary>
        /// 接收客户端的连接
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public override bool AppConnect(IConnection connection, object[] parameters)
        {
            string userName = parameters[0] as string;
            string password = parameters[1] as string;

if (password == null || password == string.Empty)
                throw new ClientRejectedException(null);

connection.Client.SetAttribute("userName", userName);
            //获取共享对象(OnLineUsers)
            ISharedObject users_so = GetSharedObject(connection.Scope, "OnLineUsers");
            if (users_so == null)
            {
                //创建共享对象
                CreateSharedObject(connection.Scope, "OnLineUsers", false);
                users_so = GetSharedObject(connection.Scope, "OnLineUsers");
            }
            //更新共享对象
            users_so.SetAttribute(userName, userName);
            return true;
        }

/// <summary>
        /// 加入房间
        /// </summary>
        /// <param name="client"></param>
        /// <param name="room"></param>
        /// <returns></returns>
        public override bool RoomJoin(IClient client, IScope room)
        {
            Trace.WriteLine("加入房间 " + room.Name);
            return true;
        }

/// <summary>
        /// 离开房间
        /// </summary>
        /// <param name="client"></param>
        /// <param name="room"></param>
        public override void RoomLeave(IClient client, IScope room)
        {
            Trace.WriteLine("离开房间 " + room.Name);
            base.RoomLeave(client, room);
        }

/// <summary>
        /// 用户退出
        /// </summary>
        /// <param name="connection"></param>
        public override void AppDisconnect(IConnection connection)
        {
            string userName = connection.Client.GetAttribute("userName") as string;
            ISharedObject users_so = GetSharedObject(connection.Scope, "OnLineUsers");
            if (users_so != null)
            {
                //从共享对象中移除当前退出系统用户
                users_so.RemoveAttribute(userName);
            }
            base.AppDisconnect(connection);
        }
    }
}

开发好了ApplicationAdapter,还需要对此ApplicationAdapter进行通信配置,在FluorineFx的应用程序目录中添加app.config并进行如下配置:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <application-handler type="Fx.Adapter.MyApp"/>
</configuration>

另外还需要配置一个客户端方法的通信通道,通过FluorineFx网站下的WEB-INF/flex/service-config.xml配置:

<?xml version="1.0" encoding="utf-8" ?>
<services-config>

<channels>

<channel-definition id="my-rtmp" class="mx.messaging.channels.RTMPChannel">
               <endpoint uri="rtmp://{server.name}:1617" class="flex.messaging.endpoints.RTMPEndpoint"/>
          </channel-definition>

</channels>

</services-config>

如上便完成了服务器端的开发,在flash/felx客户端通过NetConnection去连接应用,并根据当前的连接去连接服务器端的远程共享对象,最后通过异步事件来实现数据同步更新。如下程序运行截图:

此时开多个浏览器窗口测试,不同窗口使用不同的用户名登录,可以很清楚的看到,我们已经实现了在线用户的数据同步功能,可以及时的反映用户上线离线,可以及时的同步在线用户列表的数据。

另外远程共享对象还有一个功能非常强大的特性方法,就是连接到共享对象的客户端之间可以直接广播消息(客户端调用客户端的方法)。就以上面在线用户的案例为例,用户成功登陆服务器我需要广播一条消息,用户退出了我也需要广播一条消息,要实现这个功能就需要通过远程共享的客户端呼叫 (send()方法)来实现,如下代码块:

private function onCallClient(message:String):void
{
    so.send("onSayMessage",message);
}

远程共享对象的send()方法调用了onSayMessage这个客户端方法来实现对连接到共享对象上的所有客户端广播消息,那么我们的在定义一个onSayMessage方法,如下:

/**
 * 接受客户端呼叫---此方法必须是public修饰
 */
public function onSayMessage(message:Object):void
{
    traceWriteln(message.toString());
}

private function traceWriteln(param:String):void
{
   txtTraceArea.htmlText += param + "\n";
   txtTraceArea.validateNow();
   txtTraceArea.verticalScrollPosition = txtTraceArea.maxVerticalScrollPosition;
}

如果想实现用户退出广播,可以通过服务器端RPC的方法调用客户端的方法来实现,关于RPC请查看《Flex与.NET互操作(十一):基于FluorineFx.Net的及时通信应用(Remote Procedure Call)(二)》有详细介绍。下面是Flex客户端的完整代码:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"  
    width="530" height="378" backgroundGradientAlphas="[1.0, 1.0]" 
    backgroundGradientColors="[#000000, #686868]" fontSize="12">
    <mx:Script>
        <![CDATA[
            import mx.controls.Alert;
            import dotnet.fluorinefx.VO.UserInfo;

private var nc:NetConnection;
            private var so:SharedObject;
            private var info:UserInfo;

private function connectionServer(event:MouseEvent):void
            {
                info = new UserInfo();
                info.UserName = this.txtUserName.text;
                info.Password = this.txtPassword.text;

nc = new NetConnection();
                nc.connect("rtmp://localhost:1617/SOAPP",info.UserName,info.Password);
                nc.addEventListener(NetStatusEvent.NET_STATUS,onStatusHandler);
                nc.client = this;

this.txtUserName.text="";
                this.txtPassword.text="";
                this.txtUserName.setFocus();
            }

private function onStatusHandler(event:NetStatusEvent):void
            {
                this.connStatus.text = "连接状态:" + event.info.code;
                if(event.info.code == "NetConnection.Connect.Success")
                {
                    //连接远程共享对象
                    so = SharedObject.getRemote("OnLineUsers",nc.uri,false);
                    if(so)
                    {
                        so.addEventListener(SyncEvent.SYNC,onSyncHandler);
                        so.connect(nc);
                        so.client = this;
                    }
                    onCallClient("用户【 <font color=\"#4100b9\">"+info.UserName+"</font>】登陆了系统!");
         ");
                }
            }

private function onSyncHandler(event:SyncEvent):void
            {
                var temp:Array = new Array();
                for(var u:String in so.data)
                {
                    //traceWriteln("异步事件->共享对象:" + u + ":" + so.data[u]);
                    temp.push(so.data[u]);
                }
                this.userList.dataProvider = temp;
            }

private function traceWriteln(param:String):void
            {
                txtTraceArea.htmlText += param + "\n";
                txtTraceArea.validateNow();
                txtTraceArea.verticalScrollPosition = txtTraceArea.maxVerticalScrollPosition;
            }

private function onCallClient(message:String):void
            {
                so.send("onSayMessage",message);
            }
            /**
             * 接受客户端呼叫
             */
            public function onSayMessage(message:Object):void
            {
                traceWriteln(message.toString());
            }
        ]]>
    </mx:Script>
    <mx:Label x="24" y="134" id="connStatus" width="288" color="#FFFFFF"/>
    <mx:List x="342" y="10" height="347" width="160" id="userList" >
    </mx:List>
    <mx:Form x="24" y="10" width="236">
        <mx:FormItem label="用户名:" color="#FFFFFF">
            <mx:TextInput id="txtUserName" width="130" color="#000000"/>
        </mx:FormItem>
        <mx:FormItem label="密  码:" color="#FFFFFF">
            <mx:TextInput id="txtPassword" width="130" 
                color="#000000" displayAsPassword="true"/>
        </mx:FormItem>
        <mx:FormItem label="">
            <mx:Button label="登陆服务器" click="connectionServer(event)" 
                enabled="{this.txtUserName.text.length>0?true:false}" color="#FFFFFF"/>
        </mx:FormItem>
    </mx:Form>
    <mx:TextArea x="24" y="174" width="288" height="153" alpha="1.0" 
        backgroundColor="#F2D2D2" backgroundAlpha="0.26" color="#FFFFFF" 
        id="txtTraceArea" borderColor="#FFFFFF"/>
</mx:Application>
       }
            }

private function onSyncHandler(event:SyncEvent):void
            {
                var temp:Array = new Array();
                for(var u:String in so.data)
                {
                    //traceWriteln("异步事件->共享对象:" + u + ":" + so.data[u]);
                    temp.push(so.data[u]);
                }
                this.userList.dataProvider = temp;
            }

private function traceWriteln(param:String):void
            {
                txtTraceArea.htmlText += param + "\n";
                txtTraceArea.validateNow();
                txtTraceArea.verticalScrollPosition = txtTraceArea.maxVerticalScrollPosition;
            }

private function onCallClient(message:String):void
            {
                so.send("onSayMessage",message);
            }
            /**
             * 接受客户端呼叫
             */
            public function onSayMessage(message:Object):void
            {
                traceWriteln(message.toString());
            }
        ]]>
    </mx:Script>
    <mx:Label x="24" y="134" id="connStatus" width="288" color="#FFFFFF"/>
    <mx:List x="342" y="10" height="347" width="160" id="userList" >
    </mx:List>
    <mx:Form x="24" y="10" width="236">
        <mx:FormItem label="用户名:" color="#FFFFFF">
            <mx:TextInput id="txtUserName" width="130" color="#000000"/>
        </mx:FormItem>
        <mx:FormItem label="密  码:" color="#FFFFFF">
            <mx:TextInput id="txtPassword" width="130" 
                color="#000000" displayAsPassword="true"/>
        </mx:FormItem>
        <mx:FormItem label="">
            <mx:Button label="登陆服务器" click="connectionServer(event)" 
                enabled="{this.txtUserName.text.length>0?true:false}" color="#FFFFFF"/>
        </mx:FormItem>
    </mx:Form>
    <mx:TextArea x="24" y="174" width="288" height="153" alpha="1.0" 
        backgroundColor="#F2D2D2" backgroundAlpha="0.26" color="#FFFFFF" 
        id="txtTraceArea" borderColor="#FFFFFF"/>
</mx:Application>

(0)

相关推荐

  • Flex与.NET互操作(十二):FluorineFx.Net的及时通信应用(Remote Shared Objects)(三)

    FluorineFx所提供的远程共享对象(Remote Shared Objects)和FMS的共享对象的功能是一样,对于熟悉FMS开发的朋友来说,学习FluorineFx的远程共享对象是非常简单的. 共享对象可以在服务器端创建,也可以在客户端创建.在客户端创建共享对象的方法和使用FMS开发是一样的,创建一个 NetConnection对象,通过该对象的connect()方法连接到服务器,然后通过SharedObject.getRemote()方法就可以在客户端创建一个远程共享对象.如下实例代码

  • Flex与.NET互操作(十):FluorineFx.Net的及时通信应用(ApplicationAdapter)(一)

    应用程序适配器对象也就相当于是一个Flash媒体服务器应用程序的对象. 使用FluorineFx.Net开发及时通信应用,我们可以通过ASP.NET网站来宿主,一个ASP.NET网站可以承载多个实时通讯应用程序.这些应用程序都存储ASP.NET网站的根目录下指定文件夹的根目录中.如下图示: 在开发FluorineFx的及时通信应用的时候,按照FluorineFx的目录结构配置ASP.NET的站点目录是非常简单的,只需要在ASP.NET站点下面建立一个名为apps的目录,那么FluorineFx就

  • Flex与.NET互操作(十一):FluorineFx.Net的及时通信应用(Remote Procedure Call)(二)

    NET的服务器端同样也可以非常方便的呼叫客户端,调用客户端的方法(比如实现系统广播). 一.客户端的RPC(客户端调用服务器端) 要想实现客户端访问服务器端的方法,首先得对ActionScript中的NetConnection比较熟悉,该类提供了一个示例方法call()专们用来做RPC访问,该方法的定义如下: public function call(command:String, responder:Responder,  arguments):void 比如说我们在开发一个及时应用的时候,所

  • Flex与.NET互操作(八) 使用FluorineFx网关实现远程访问

    于此,本文将使用FluorineFx网关来提供数据服务等多项功能来介绍通过FluorineFx实现远程访问的相关知识点. FluorineFx提供的远程访问包括有很多方面的知道点,本文只介绍其中的三个知识点:访问远程对象返回对象,返回DataTable,返回DataSet对象.FluorineFx安装包里自带有相关的示例程序,要学习更多可直接参考这些示例程序. 在实现访问前我们同样来做一些准备工作,建立好远程对象,如下: 1 namespace Fluorine.ServiceLibrary 2

  • Flex与.NET互操作(十三):FluorineFx.Net实现视频录制与视频回放

    通过它我们可以非常方便的实现在线视频录制.视频直播.视频聊天以及视频会议等类似应用程序的开发. 在<FMS3系列(四):在线视频录制.视频回放 >这篇文章里我写了通过FMS来实现在线视频录制和视频回放的功能,客户端的开发和这篇文章是相同的,不同的是本文将使用Flex来开发. 首先我们来看看使用FluorineFx服务端是如何开发的,建立ApplicationAdapter是必然的,这里我们为本文中的示例程序建立的ApplicationAdapter为VideoApplication,并为其添加

  • 十二款世界顶级杀毒软件下载,有序列号全可免费升级

    2006年世界顶级杀毒软件排名 金奖:   BitDefender银奖:   Kaspersky铜奖:   F-Secure Anti-Virus第四名: PC-cillin第五名: ESET Nod32第六名: McAfee VirusScan第七名: Norton AntiVirus第八名: AVG Anti-Virus第九名: eTrust EZ Antivirus第十名: Norman Virus Control第十一名:AntiVirusKit第十二名:AVAST!这里是排名的国外网站

  • Vuejs第十二篇之动态组件全面解析

    什么是组件? 组件(Component)是 Vue.js 最强大的功能之一.组件可以扩展 HTML 元素,封装可重用的代码.在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功能.在有些情况下,组件也可以是原生 HTML 元素的形式,以 is 特性扩展. 本篇资料是小编参考官方文档的基础上整理的一篇更加细致的说明,代码更多更全,非常适合新手学习. 官方文档: http://cn.vuejs.org/guide/components.html#u52A8_u6001_u7EC4_u

  • MS SQL Server获取十二个月份的英文缩写

    如果使用DATENAME()函数是取得月份的英文全称,但报表需要,只需显示月份名称缩写即可. 十二个月份的英文缩写,只有五月份是全称与缩写一样,其它月份的缩写仅是取前三位字母.因此Insus.NET写成一个自定义函数: 复制代码 代码如下: -- ============================================= -- Author: Insus.NET -- Create date: 2012-12-18 -- Description: Get Month abbrev

  • 六十二、从DOS直接入网NT

    六十二.从DOS直接入网NT   热点网络 作为NT网的用户,你可能遇到过这种情况:网络硬件已连好,服务器也已安装Windows NT Server,并进行了各项必要的配置,但由于准备入网的计算机没有光驱,所以无法安装Windows 95,自然也无法利用Windows 95实现入网.这时你该怎么办呢?能不能从DOS直接入网呢?答案是肯定的.回到服务器,你将发现Windows NT为DOS环境下的联网提供了解决办法,一经实践,OK!整个过程可分为以下三步: 一.制作网络安装盘 1.启动服务器的NT

  • 保存和配置系统硬件注册信息—注册表使用全攻略之十二

    保存和配置系统硬件注册信息-注册表使用全攻略之十二 电脑用的时间长了,经常要更换一些硬件设备,重复安装驱动程序也就成了家常便饭,这样就致使电脑中残留下很多硬件注册信息,系统启动时就会试图与不存在的设备通讯,从而导致系统速度的下降.如何删除这些注册信息呢?格式化么?太麻烦了吧! 其实Windows有个"硬件配置文件"功能,它是用来告诉电脑在启动时启动哪些硬件设备,第一次安装Windows时,系统就默认创建了一个配置文件"Original Configuration"(

随机推荐