.Net Remoting 应用实例 DotNetRemotingChat

来源:互联网 发布:淘宝直通车排序 编辑:程序博客网 时间:2024/05/19 12:12

 

最近研究了一下.Net Remoting技术,做了个实例,简单记录下来,以便参考。

 

概念性的东西不多说了,前面也转载了几篇文章,写的都不错,这里主要说说我的这个实例的实现过程。

 

这个实例包含三个项目:Chat_Server,Chat_Client,Chat_CommonLib,即服务端,客户端和公共程序集,一般.Net Remoting都包含这三块。

 

先来看看Chat_CommonLib项目,该项目是一个类库程序,包含两个接口IRemoteObjectFactory,IRemoteObject,一个类EventWrapper和一个公共委托MessagedEventHandler。

 

namespace Chat_CommonLib{    public interface IRemoteObjectFactory    {        IRemoteObject CreateInstance(string user);    }}


 

namespace Chat_CommonLib{    public delegate void MessagedEventHandler(string msg);    public interface IRemoteObject    {        string User { get; set; }        void Connect();        void Disconnect();        void SendMessage(string msg);        void SubMessage(string msg);        event MessagedEventHandler Messaged;    }}


namespace Chat_CommonLib{    public class EventWrapper:MarshalByRefObject    {        public event MessagedEventHandler Messaged;        public void SubMessage(string msg)        {            if (Messaged != null)            {                MessagedEventHandler temp = null;                foreach (Delegate del in Messaged.GetInvocationList())                {                    try                    {                        temp = (MessagedEventHandler)del;                        temp(msg);                    }                    catch (Exception ex)                    {                        //RemoteObjectFactory.SubLogger("Send event message fail.\r\n" + ex.ToString());                    }                }            }        }        public override object InitializeLifetimeService()        {            return null;        }    }}


在服务端实现远程对象,注意远程对象及其工厂都要继承MarshalByRefObject,并实现先前定义的接口

namespace Chat_Server.Codes{    class RemoteObjectFactory : MarshalByRefObject, IRemoteObjectFactory    {        public static event Action<string> Logger;        public static List<IRemoteObject> RemoteObjects = new List<IRemoteObject>();        public IRemoteObject CreateInstance(string user)        {            IRemoteObject remoteObject = new RemoteObject(user);            RemoteObjects.Add(remoteObject);            return remoteObject;        }        public static void SubLogger(string msg)        {            if (Logger != null)            {                Logger(msg);            }        }        public static void SendMessage(IRemoteObject user, string msg)        {            user.SubMessage(msg);        }        public static void SendMessage(IRemoteObject user, string msg, bool self)        {            foreach (IRemoteObject _user in RemoteObjects)            {                if (_user != user || self)                {                    SendMessage(_user, msg);                }            }        }        public override object InitializeLifetimeService()        {            return null;        }    }}


 

namespace Chat_Server.Codes{    class RemoteObject : MarshalByRefObject, IRemoteObject    {        public event MessagedEventHandler Messaged;        private string mUser;        public string User        {            get            {                return mUser;            }            set            {                mUser = value;            }        }        public RemoteObject(string user)        {            mUser = user;        }        public void Connect()        {            string msg = string.Format("{0}\tConnected.", mUser);            RemoteObjectFactory.SubLogger(msg);            RemoteObjectFactory.SendMessage(this, "Server connected.");            RemoteObjectFactory.SendMessage(this, msg, false);        }        public void Disconnect()        {            string msg = string.Format("{0}\tDisconnected.", mUser);            RemoteObjectFactory.RemoteObjects.Remove(this);        }        public void SubMessage(string msg)        {            if (Messaged != null)            {                MessagedEventHandler temp = null;                foreach (Delegate del in Messaged.GetInvocationList())                {                    try                    {                        temp = (MessagedEventHandler)del;                        temp(msg);                    }                    catch (Exception ex)                    {                        RemoteObjectFactory.SubLogger("Send event message fail.\r\n" + ex.ToString());                    }                }            }        }        public override object InitializeLifetimeService()        {            return null;        }        public void SendMessage(string msg)        {            RemoteObjectFactory.SendMessage(this, this.User + "\t" + msg, true);        }    }}


 注册通道,我这里采用服务端SingleTon激活方式,但是功能上看类似于客户端激活方式,因为远程对象实在客户端实例化的,并且每个客户端独立使用一个远程对象。

服务端通道注册:

private bool CreateRemoteObject()        {            try            {                SoapServerFormatterSinkProvider soap = new SoapServerFormatterSinkProvider();                BinaryServerFormatterSinkProvider binary = new BinaryServerFormatterSinkProvider();                soap.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;                binary.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;                soap.Next = binary;                Hashtable table = new Hashtable();                table.Add("port", II_ServerPort);                TcpChannel channel = new TcpChannel(table, null, soap);                ChannelServices.RegisterChannel(channel, false);                RemotingConfiguration.ApplicationName = "RemotingChat";                RemotingConfiguration.RegisterWellKnownServiceType(typeof(RemoteObjectFactory), "RemotingChat", WellKnownObjectMode.Singleton);            }            catch (Exception ex)            {                IS_Error = ex.ToString();                return false;            }            return true;        }


 

客户端通道注册及远程对象的激活:

private bool MakeConnection()        {            try            {                SoapServerFormatterSinkProvider soap = new SoapServerFormatterSinkProvider();                BinaryServerFormatterSinkProvider binary = new BinaryServerFormatterSinkProvider();                soap.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;                binary.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;                soap.Next = binary;                Hashtable table = new Hashtable();                table.Add("port", "0");                TcpChannel channel = new TcpChannel(table, null, soap);                ChannelServices.RegisterChannel(channel, false);                string url = string.Format("tcp://{0}:{1}/RemotingChat", IS_ServerIP, II_ServerPort);                IRemoteObjectFactory objectFactory = (IRemoteObjectFactory)Activator.GetObject(typeof(IRemoteObjectFactory), url);                I_RemoteObject = objectFactory.CreateInstance(GetCurrentIP());                EventWrapper eventWrapper = new EventWrapper();                eventWrapper.Messaged += new MessagedEventHandler(eventWrapper_Messaged);                I_RemoteObject.Messaged += new MessagedEventHandler(eventWrapper.SubMessage);                I_RemoteObject.Connect();            }            catch (Exception ex)            {                IS_Error = ex.ToString();                return false;            }            return true;        }


 主要代码就如以上所述,下面重点说说其中要注意的几点:

 

1、工厂模式,工厂模式是一种极为常见的编程方式,其核心就一个CreateInstance方式,能够返回指定类型的实例,在这个实例中RemoteObject就工厂RemoteObjectFactory返回的一个对象,可以在客户端调用这个方法。

 

2、代码组织,由于远程对象在服务端和客户端都要引用,一个好的办法就是利用接口,在接口中定义远程对象的各个方法事件等,在服务端具体实现,而客户端只需引用对应的接口就行,并且接口和其他可能需要封送的的类都放在公共程序集中,这样代码更加清晰,引用也方便。

 

3、远程对象事件及事件的订阅,这是最难也是最容易出错的地方,尤其客户端订阅服务端事件。客户端是通过代理引用远程对象的,因而客户端引用的并不是真正的远程对象,而是其代理,所以对其订阅事件并不能这真订阅到远程对象本身。一个好的办法就是包装事件,即设计一个事件包装器类EventWrapper,其中的事件和远程对象的定义样,这个类还必须继承MarshalByRefObject以实现远程封送,通过这个中间类可以实现客户端订阅服务端事件。

原创粉丝点击