专栏首页菩提树下的杨过FluorineFx:基于RSO(远程共享对象)的文本聊天室

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

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

原理:

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

运行截图:

服务端代码:

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)(三)

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • FluorineFx:视频录制及回放(Flash/AS3环境)

    如果不考虑安全因素(指任何人都可连接FluorineFx进行视频录制,而不需要登录认证),其实服务端不用写一行代码,仅需要在apps目录下建一个子目录当作应用,...

    菩提树下的杨过
  • Flash在线拍摄用户头象

    很多网站在上传用户头象时,除了传统方式上传外,都支持在线摄像头拍照并做简单编辑,完成之后再将图象数据提交到服务端(比如ASP.Net),这几天正好需要这个功能,...

    菩提树下的杨过
  • ExtJs+WCF+LINQ实现分页Grid

    上篇文章《用ExtJs+Linq+Wcf打造简单grid 》,这个网格控件不带分页,本文在上文的基础上添加分页功能,文中会着重介绍如何在用LINQ返回分页数据,...

    菩提树下的杨过
  • 上下div高度动态自适应--另类处理方案

         这段时间在工作中遇到一个看似较为棘手的问题。问题描述:查询报表页面分为上下两部分,上部分为条件输入区域,下部分为报表展示区域。客户要求做到默认满屏(但...

    sam dragon
  • PHP高级编程之守护进程

    PHP高级编程之守护进程 摘要 2014-09-01 发表 2015-08-31 更新 2015-10-20 更新,增加优雅重启 ---- 目录 1. 什么是守...

    netkiller old
  • PHP高级编程之守护进程

    PHP高级编程之守护进程 摘要 2014-09-01 发表 2015-08-31 更新 2015-10-20 更新,增加优雅重启 ---- 目录 1. 什么是守...

    netkiller old
  • mpvue开发小程序过程中遇到的问题

    原生小程序开发方式与vue有些类似,所以用过vue的前端er会很容易上手。但是原生的开发体验实在糟糕,在前端组件化的今天用原生开发组件显得很无力。对于习惯vue...

    javascript.shop
  • 等了那么久,终于等到新游戏啦!大炮英雄Cocos Creator实现,关注获取代码!

    摆放一个背景图,在背景图上添加背景地面、开始按钮、4个角色选择按钮、游戏logo。

    张晓衡
  • React Async Rendering

    React放出Fiber(2017/09/26发布的v16.0.0带上去的)到现在已经快1年了,到目前(2018/06/13发布的v16.4.1)为止,最核心的...

    ayqy贾杰
  • 竟然可以用 effect 玩水?Cocos Creator 3D !

    最近逛论坛时,看到一位大佬在分享各种 shader 特效。基于其中的水波 shader ,白玉无冰写了一个玩水效果!文章底部获取完整代码!还可以试试水哦!

    白玉无冰

扫码关注云+社区

领取腾讯云代金券