Remoting事件機制續

javaprogramers發表於2006-05-14
(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地址後面跟上隨機數,是因為可能在一個機器上會開啟多個客戶端,需要在這個時候能在伺服器端區分多個客戶端。



備註:我的所有例子都是在客戶端和伺服器端部署遠端物件的,其實這個做法不是很好,我們應該僅僅把介面部署在兩地,遠端物件僅僅部署在伺服器端即可。

相關文章