FluorineFx:基于RSO(远程共享对象)的文本聊天室

在前一篇“FluorineFx:远程共享对象(Remote SharedObjects)”里,已经大致知道了在FluorineFX中如何使用RSO,这一篇将利用RSO完成一个简单的文本聊天室。

原理:

RSO对象中,创建二个属性:msg和online,分别用来保存"用户每次发送的聊天内容"以及"在线用户列表"

运行截图:

FluorineFx:基于RSO(远程共享对象)的文本聊天室

服务端代码:

using System.Collections;
using FluorineFx.Messaging.Api;
using FluorineFx.Messaging.Api.SO;

namespace _03_RSO_Chat
{
    public class ChatSecurityHandler : ISharedObjectSecurity
    {
        #region ISharedObjectSecurity Members

        //是否允许连接
        public bool IsConnectionAllowed(ISharedObject so)
        {
            return true;
        }

        //是否允许创建rso对象(下面的代码仅允许创建名为chat的rso对象)
        public bool IsCreationAllowed(IScope scope, string name, bool persistent)
        {
            if (name=="chat")
            {
                return false;
            }
            else
            {
                return true;
            }
        }

        //是否允许删除
        public bool IsDeleteAllowed(ISharedObject so, string key)
        {
            return false;
        }

        //是否允许rso对象向服务端send指定回调方法(下面的代码仅允许发送名为drop的回调方法)
        public bool IsSendAllowed(ISharedObject so, string message, IList arguments)
        {
            return true;
        }

        //rso对象的属性是否可写
        public bool IsWriteAllowed(ISharedObject so, string key, object value)
        {
            return true;
        }

        #endregion
    }
}

ChatApplication.cs

using FluorineFx.Messaging.Adapter;
using FluorineFx.Messaging.Api;
using FluorineFx.Messaging.Api.SO;
using System.Collections;
using System;
using System.Collections.Generic;
using System.Linq;


namespace _03_RSO_Chat
{
    public class ChatApplication : ApplicationAdapter
    {
        public override bool AppStart(IScope application)
        {
            RegisterSharedObjectSecurity(new ChatSecurityHandler());//注册刚才定义的安全处理Handler
            return base.AppStart(application);
        }


        /// <summary>
        /// 每当有新客户端连接到服务器时,该方法会被触发
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public override bool AppConnect(IConnection connection, object[] parameters)
        {
            string userName = string.Empty, passWord = string.Empty;

            if (parameters.Length >= 2)
            {
                userName = parameters[0].ToString();//第一个参数当作用户名
                passWord = parameters[1].ToString();//第二个参数当作密码
            }

            if (string.IsNullOrEmpty(userName))
            {
                userName = "游客" + (new System.Random()).Next(0, 9999).ToString();
            }

            //if (userName == "jimmy.yang" && passWord == "123456")//安全性校验
            //{
            if (base.AppConnect(connection, parameters))
            {
                //获取共享对象(position)
                ISharedObject iso = GetSharedObject(connection.Scope, "chat");
                if (iso == null)
                {
                    //创建共享对象
                    CreateSharedObject(connection.Scope, "chat", true);
                    iso = GetSharedObject(connection.Scope, "chat");
                }

                //更新聊天记录
                iso.SetAttribute("msg", "<font color='#0000ff'>系统:</font><font color='#ff0000'>" + userName + "</font> 进入聊天室!</font>");

                //处理在线名单
                string[] online = iso.GetAttribute("online") as string[];
                List<string> lst = new List<string>();
                if (online == null)
                {
                    lst.Add(userName);
                }
                else
                {
                    lst.AddRange(online);
                }
                if (!lst.Contains(userName))
                {
                    lst.Add(userName);
                }
                iso.SetAttribute("online", lst.ToArray());

                //更新connection的userName属性(退出时会用到)
                connection.Client.SetAttribute("userName", userName);

                return true;
            }
            else
            {
                RejectClient("连接失败,请检查服务端是否运行正常!");
                return false;
            }
            //}
            //else
            //{
            //    RejectClient("用户名或密码错误");
            //    return false;
            //}
        }


        /// <summary>
        /// 每当用户断开连接时,触发此事件
        /// </summary>
        /// <param name="connection"></param>
        public override void AppDisconnect(IConnection connection)
        {
            try
            {
                string userName = connection.Client.GetAttribute("userName") as string;

                //获取共享对象(position)
                ISharedObject iso = GetSharedObject(connection.Scope, "chat");

                //发送离线通知           
                iso.SetAttribute("msg", "<font color='#0000ff'>系统:</font><font color='#ff0000'>" + userName + "</font> 离开了聊天室!</font>");


                //处理在线名单
                string[] online = iso.GetAttribute("online") as string[];
                List<string> lst = new List<string>();
                if (online == null)
                {
                    lst.Add(userName);
                }
                else
                {
                    lst.AddRange(online);
                }
                if (lst.Contains(userName))
                {
                    lst.Remove(userName);
                }
                iso.SetAttribute("online", lst.ToArray());
            }
            catch { }

            base.AppDisconnect(connection);
        }
    }
}

Flash客户端代码:

package 
{
	import fl.controls.Button;

	import flash.display.SimpleButton;
	import flash.display.Sprite;
	import flash.events.MouseEvent;
	import flash.events.NetStatusEvent;
	import flash.events.SyncEvent;
	import flash.net.NetConnection;
	import flash.net.SharedObject;
	import flash.text.TextField;
	import flash.events.KeyboardEvent;
	import flash.ui.Keyboard;

	public class Chat extends Sprite
	{

		private var _btnConn:Button;
		private var _nc:NetConnection;
		private var _remoteUrl:String;
		private var _rso:SharedObject;

		private var _txtAppName:TextField;
		private var _txtContent:TextField;
		private var _txtIP:TextField;
		private var _txtOnline:TextField;
		private var _txtPassWord:TextField;
		private var _txtPort:TextField;

		private var _txtSend:TextField;
		private var _txtUserName:TextField;

		public function Chat()
		{		
			this._txtIP = txtIP;
			this._txtPort = txtPort;
			this._txtAppName = txtAppName;
			this._btnConn = btnConn;
			this._txtContent = txtContent;
			this._txtOnline = txtOnline;
			this._txtUserName = txtUserName;
			this._txtPassWord = txtPassWord;
			this._txtSend = txtSend;

			this._nc=new NetConnection();
			this._nc.addEventListener(NetStatusEvent.NET_STATUS, net_status);
			//trace(this._btnLogin);
			this._btnConn.addEventListener(MouseEvent.CLICK, btnConn_Click);


			this._txtIP.text = "127.0.0.1";
			this._txtPort.text = "1935";
			this._txtUserName.text = "游客" + Math.floor(Math.random()*10000);
			this._txtPassWord.text = "123456";			

		}



		private function btnConn_Click(e:MouseEvent):void
		{
			_remoteUrl = "rtmp://" + this._txtIP.text + ":" + this._txtPort.text + "/" + this._txtAppName.text;
			//trace(this._remoteUrl);
			_nc.connect(this._remoteUrl, this._txtUserName.text, this._txtPassWord.text);
			_nc.client = this;
		}

		private function net_status(e:NetStatusEvent):void
		{
			//trace(e.info.code);
			if (e.info.code == "NetConnection.Connect.Success")
			{
				_rso = SharedObject.getRemote("chat",this._nc.uri,true);
				this._rso.addEventListener(SyncEvent.SYNC,sync_handler);
				this._rso.connect(this._nc);
				this._rso.client = this;
				this._txtContent.htmlText = "<font color='#009933'>服务端连接成功!</font><br/>";
				this._txtSend.addEventListener(KeyboardEvent.KEY_UP,txtsend_key_up);
			}
			else
			{
				this._txtContent.htmlText = "<font color='#ff0000'>服务端连接失败!</font><br/>";
			}
		}

		private function sync_handler(e:SyncEvent):void
		{
			//trace(this._rso.data.msg);
			//更新聊天记录
			if (this._rso.data.msg != undefined)
			{
				var msg:String = this._rso.data.msg + "<br/>";
				
				var msgTxt:String = msg.replace(/<.+?>/gi,"");
				var chatTxt:String = this._txtContent.htmlText.replace(/<.+?>/gi,"");
				
				//防止重复显示
				if (chatTxt.indexOf(msgTxt)==-1)
				{
					this._txtContent.htmlText +=  msg;
				}
				
				//trace(msg);
				//trace(this._txtContent.htmlText);
				
				this._txtContent.scrollV = this._txtContent.maxScrollV;
			}

			//更新在线列表
			if (this._rso.data.online != undefined)
			{
				this._txtOnline.text = (this._rso.data.online as Array).join('\n');
			}
		}

		private function txtsend_key_up(e:KeyboardEvent):void
		{
			//trace(e);
			if (this._txtSend.text.length > 0 && e.ctrlKey && e.keyCode == Keyboard.ENTER)
			{
				this._rso.setProperty("msg","<font color='#ff0000'>" + this._txtUserName.text + "</font> 说:" + this._txtSend.text);
				this._txtSend.text = "";
			}
		}
	}
}

示例源文件下载:http://cid-2959920b8267aaca.office.live.com/self.aspx/Flash/FluorineFx^_Demo^_03.rar

另:flex环境下fluorineFx的rso应用,建议大家同步参看beniao兄的文章Flex与.NET互操作(十二):FluorineFx.Net的及时通信应用(Remote Shared Objects)(三)

上一篇:利用Xtrabackup工具备份及恢复


下一篇:RxJs SwitchMapTo 操作符之移花接木