程序人生

人在他乡

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
一步一步学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(); 
        } 
    } 

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



备注:我的所有例子都是在客户端和服务器端部署远程对象的,其实这个做法不是很好,我们应该仅仅把接口部署在两地,远程对象仅仅部署在服务器端即可。
posted on 2010-06-10 21:20  邹标财  阅读(160)  评论(0编辑  收藏  举报