Remoting事件機制續

(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地址後面跟上隨機數,是因爲可能在一個機器上會打開多個客戶端,需要在這個時候能在服務器端區分多個客戶端。

備註:我的所有例子都是在客戶端和服務器端部署遠程對象的,其實這個做法不是很好,我們應該僅僅把接口部署在兩地,遠程對象僅僅部署在服務器端即可。 
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章