一步一步学Remoting之六:事件(2)

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地址后面跟上随机数,是因为可能在一个机器上会打开多个客户端,需要在这个时候能在服务器端区分多个客户端。

 

备注:我的所有例子都是在客户端和服务器端部署远程对象的,其实这个做法不是很好,我们应该仅仅把接口部署在两地,远程对象仅仅部署在服务器端即可。

原文地址:https://www.cnblogs.com/Leo_wl/p/1733061.html