原文转自 http://www.cnblogs.com/lovecherry/archive/2005/05/24/161437.html
遗留问题
(1)关闭一个客户端以后会影响其他的客户端事件
原因:客户端没有取消事件订阅就关闭了,触发事件的时候找不到事件订阅者
解决:遍历委托链,找到异常的对象,从委托链中卸下
(2)服务器端对客户端广播,客户端能收到其他客户端的事件处理信息
原因:使用了Singleton模式,共享远程对象
解决:因为需要远程对象有状态且不共享实例,所以只有客户端激活可以选择修改后的服务端:
using System; using System.Collections; using System.Runtime.Remoting; using System.Runtime.Remoting.Channels; using System.Runtime.Remoting.Channels.Tcp; using System.Runtime.Serialization.Formatters; namespace RemoteServer { class MyServer { [STAThread] static void Main(string[] args) { RemotingConfiguration.ApplicationName="RemoteObject.MyObject"; RemotingConfiguration.RegisterActivatedServiceType(typeof(RemoteObject.MyObject)); BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider(); BinaryClientFormatterSinkProvider clientProvider = new BinaryClientFormatterSinkProvider(); serverProvider.TypeFilterLevel = TypeFilterLevel.Full; IDictionary props = new Hashtable(); props["port"]=8888; TcpChannel channel = new TcpChannel(props,clientProvider,serverProvider); ChannelServices.RegisterChannel(channel); Console.ReadLine(); } } }
修改后的远程对象:
using System; namespace RemoteObject { [Serializable] public class MyEventArgs:EventArgs { private int _rate; private string _ip; public int Rate { get { return _rate; } } public string IP { get { return _ip; } } public MyEventArgs(int rate,string ip) { this._rate=rate; this._ip=ip; } } public class MyObject:MarshalByRefObject { public delegate void MyEventHandler(object sender,MyEventArgs e); public event MyEventHandler MyEvent; public string tmp; public int ALongTimeMethod(int a,int b,int time,string ip) { Console.WriteLine("来自"+ip+"的异步方法开始"); for(int i=1;i<=10;i++) { System.Threading.Thread.Sleep(time); Console.WriteLine("来自"+ip+"的异步方法完成了"+i*10+"%"); OnMyEvent(new MyEventArgs(i,ip)); } Console.WriteLine("来自"+ip+"的异步方法结束"); return a+b; } protected void OnMyEvent(MyEventArgs e) { if (MyEvent!=null) { foreach(Delegate d in MyEvent.GetInvocationList()) { try { ((MyEventHandler)d)(this,e); } catch { MyEvent-=(MyEventHandler)d; } } } } } public class EventClass:MarshalByRefObject { public void MyEvent(object sender,MyEventArgs e) { if(((MyObject)sender).tmp==e.IP) Console.WriteLine("异步方法完成了"+e.Rate*10+"%"); } } }
修改后的客户端:
using System; using System.Net; using System.Collections; using System.Text; using System.Runtime.Remoting; using System.Runtime.Remoting.Channels; using System.Runtime.Remoting.Channels.Tcp; using System.Runtime.Serialization.Formatters; class MyClient { private delegate int MyDelegate(int a,int b,int time,string ip); private static MyDelegate md; static RemoteObject.MyObject app; static RemoteObject.EventClass ec; static DateTime dt; [STAThread] static void Main(string[] args) { dt=DateTime.Now; RemotingConfiguration.RegisterActivatedClientType(typeof(RemoteObject.MyObject),"tcp://localhost:8888/RemoteObject.MyObject"); BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider(); BinaryClientFormatterSinkProvider clientProvider = new BinaryClientFormatterSinkProvider(); serverProvider.TypeFilterLevel = TypeFilterLevel.Full; IDictionary props=new Hashtable(); props["port"]=0; TcpChannel channel = new TcpChannel(props,clientProvider,serverProvider); ChannelServices.RegisterChannel(channel); app=new RemoteObject.MyObject(); ec=new RemoteObject.EventClass(); app.MyEvent+=new RemoteObject.MyObject.MyEventHandler(ec.MyEvent); md=new MyDelegate(app.ALongTimeMethod); AsyncCallback ac=new AsyncCallback(MyClient.CallBack); IPHostEntry ipHE=Dns.GetHostByName(Dns.GetHostName()); Random rnd=new Random(System.Environment.TickCount); string ip=ipHE.AddressList[0].ToString()+"("+rnd.Next(100000000).ToString()+")"; app.tmp=ip; IAsyncResult Iar=md.BeginInvoke(1,2,500,ip,ac,null); Method(); Console.WriteLine("用了"+((TimeSpan)(DateTime.Now-dt)).TotalSeconds+"秒"); ChannelServices.UnregisterChannel(channel); Console.ReadLine(); } public static void CallBack(IAsyncResult Iar) { if(Iar.IsCompleted) { Console.WriteLine("结果是"+md.EndInvoke(Iar)); app.MyEvent-=new RemoteObject.MyObject.MyEventHandler(ec.MyEvent); } } public static void Method() { Console.WriteLine("主线程方法开始"); System.Threading.Thread.Sleep(5000); Console.WriteLine("主线程方法结束"); } }
之所以要在ip地址后面跟上随机数,是因为可能在一个机器上会打开多个客户端,需要在这个时候能在服务器端区分多个客户端。
备注:我的所有例子都是在客户端和服务器端部署远程对象的,其实这个做法不是很好,我们应该仅仅把接口部署在两地,远程对象仅仅部署在服务器端即可。
系列文章
原文转自 http://www.cnblogs.com/lovecherry/archive/2005/05/24/161437.html