天天看點

一步一步學Remoting之六:事件(2) <轉>

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

到了午休的時間,抓緊時間繼續寫,上次說有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(); 

        } 

    } 

修改後的遠端對象:

namespace RemoteObject 

    [Serializable] 

    public class MyEventArgs:EventArgs 

        private int _rate; 

        private string _ip; 

        public int Rate 

            get 

            { 

                return _rate; 

            } 

        public string IP 

                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.Net; 

using System.Text; 

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位址後面跟上随機數,是因為可能在一個機器上會打開多個用戶端,需要在這個時候能在伺服器端區分多個用戶端。

一步一步學Remoting之六:事件(2) <轉>

備注:我的所有例子都是在用戶端和伺服器端部署遠端對象的,其實這個做法不是很好,我們應該僅僅把接口部署在兩地,遠端對象僅僅部署在伺服器端即可。

繼續閱讀