• Remoting 笔记.


    从LoveCherry的Blog的Remoting之六说起. (原文:http://www.cnblogs.com/lovecherry/archive/2005/05/23/160954.html)

    一.这是一个客户端激活模式的例子
    [原文]1.服务器端代码:

    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(); 
            } 
        } 

    [原文]2.远程对象:

    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+"%"); 
            }  
        } 


    [原文]3.客户端代码:

    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(
    "主线程方法结束"); 
        } 


    以上用了客户端激活模式: 有以下特性:
    1、客户端激活的时间是在客户端请求的时候,而服务端激活远程对象的时间是在调用对象方法的时候
    2、客户端激活可以调用自定义的构造方法,而不像服务端激活只能使用默认的构造方法
    3、客户端激活模式一旦获得客户端的请求,将为每一个客户端都建立一个实例引用.服务器的 SingleCall 模式是每个请求有各自的实例引用, SingleTon 模式每个类只有一个实例引用.
    4. 客户端激活是有状态的.服务器的 SingleTon 是有状态的,而 SingleCall 是没有状态的.

    客户端激活用法特点如下:

    1.服务器端用RemotingConfiguration.ApplicationName="RemoteObject.MyObject";来注册一个服务器Uri.
    作用是,注册客户端激活方式中,要用一个 服务器的 Uri . 客户端用RemotingConfiguration.RegisterActivatedClientType(typeof(RemoteObject.MyObject),"tcp://localhost:8888/RemoteObject.MyObject");来远程注册对象类型.
    2.注册知名类型,以便客户端在创建这些类型的时候,是从服务器端创建.
    RemotingConfiguration.RegisterActivatedServiceType(typeof(RemoteObject.MyObject));
    客户端有两种方式:一种是先注册再声明: 像这样:
            RemotingConfiguration.RegisterActivatedClientType(typeof(RemoteObject.MyObject), "tcp://localhost:8888/RemoteServer");
            app = new RemoteObject.MyObject();
    还可以:
    3.其中远程对象,要继承自  MarshalByRefObject



    二.把程序改成 服务器端激活 的 SingleTon 模式.
    [改
    SingleTon]1.服务器端代码:

            static void Main(string[] args)
            {
                RemotingConfiguration.ApplicationName 
    = "RemoteServer";
                RemotingConfiguration.RegisterWellKnownServiceType(
    typeof(RemoteObject.MyObject),"MyObject",WellKnownObjectMode.Singleton);
                RemotingConfiguration.RegisterWellKnownServiceType(
    typeof(RemoteObject.EventClass),"EventClass",WellKnownObjectMode.Singleton);
                RemotingConfiguration.RegisterWellKnownServiceType(
    typeof(RemoteObject.MyObject.MyEventHandler),"MyEventHandler",WellKnownObjectMode.Singleton);
                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();
            }


    [改SingleTon]2.客户端代码:

       static void Main(string[] args)
        {
            dt 
    = DateTime.Now;
            
    //RemotingConfiguration.RegisterWellKnownClientType(typeof(RemoteObject.MyObject), "tcp://localhost:8888/RemoteServer");
            
    //RemotingConfiguration.RegisterActivatedClientType(typeof(RemoteObject.C), "tcp://localhost:8888/RemoteServer");
            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();
            app = (RemoteObject.MyObject)Activator.GetObject(typeof(RemoteObject.MyObject), "tcp://localhost:8888/MyObject");
            ec 
    = (RemoteObject.EventClass)Activator.GetObject(typeof(RemoteObject.EventClass), "tcp://localhost:8888/EventClass");//这里应该直接用 new 方法.否则.会在服务器端输出信息.为了调试说明.

            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(12500, 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(
    "主线程方法结束");
        }


    运行结果,是 所有显示内容,都在服务器端显示.其中,客户端的Main函数也可以写成:
    [改SingleTon]3.客户端的另一种写法(先用 RegisterWellKnownClientType 注册,再用 new 的方法远程声明.)

        static void Main(string[] args)
        {
            dt 
    = DateTime.Now;
            RemotingConfiguration.RegisterWellKnownClientType(
    typeof(RemoteObject.MyObject), "tcp://localhost:8888/MyObject");
            RemotingConfiguration.RegisterWellKnownClientType(
    typeof(RemoteObject.EventClass), "tcp://localhost:8888/EventClass");//这里不应该在远程注册这个对象,这里只是为了调试说明.
            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 = (RemoteObject.MyObject)Activator.GetObject(typeof(RemoteObject.MyObject), "tcp://localhost:8888/MyObject");
            
    //ec = (RemoteObject.EventClass)Activator.GetObject(typeof(RemoteObject.EventClass), "tcp://localhost:8888/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(12500, ip, ac, null);
            Method();
            Console.WriteLine(
    "用了" + ((TimeSpan)(DateTime.Now - dt)).TotalSeconds + "");
            ChannelServices.UnregisterChannel(channel);
            Console.ReadLine();
        }


    同样,结果都会显示在服务器端.这是因为: RemoteObject.EventClass 在[改SigleTon]中,注册成了服务器端的对象. 所以它就会再服务器端执行.[改SigleTon]2.中的

    ec = (RemoteObject.EventClass)Activator.GetObject(typeof(RemoteObject.EventClass), "tcp://localhost:8888/EventClass");//这里应该直接用 new 方法.否则.会在服务器端输出信息.为了调试说明.

    改为:

    ec = new RemoteObject.EventClass;

    即可.
    或把 [改SigleTon]3. 中的

    RemotingConfiguration.RegisterWellKnownClientType(typeof(RemoteObject.EventClass), "tcp://localhost:8888/EventClass");//这里不应该在远程注册这个对象,这里只是为了调试说明.

    去掉即可.

    但是.如果先后开两个客户端. 会看到. 第一个客户端会显示第二个客户端的内容.结果如下:

    主线程方法开始
    异步方法完成了10
    %
    异步方法完成了20
    %
    异步方法完成了30
    %
    异步方法完成了40
    %
    异步方法完成了10
    %
    异步方法完成了20
    %
    异步方法完成了30
    %
    异步方法完成了40
    %
    异步方法完成了50
    %
    主线程方法结束
    用了5.1273728秒
    异步方法完成了60
    %
    结果是3

    这充分说明了. SigleTon 在服务器端只有一个实例.是单件模式的. 客户端得到的,是最后一个客户所产生的进度.

    二.改为服务器端激活的SigleCall模式.
    把 [改SigleTon]1.服务器端代码中的 SingleTon 改为 SigleCall 即可.
    运行结果 服务器端显示正确. 客户端没有显示进度.
    客户端不注册EventClass .客户端也不会显示进度. 在客户端 注册 EventClass 如下:

    RemotingConfiguration.RegisterWellKnownClientType(typeof(RemoteObject.EventClass), "tcp://localhost:8888/EventClass"); 

    服务器端也不会显示客户端进度.
    这足以说明: SigleCall 是没有状态的. 所以,客户端所创建的 RemoteObject.MyObject 是无法传递属性到服务器端的. 也不能绑定委托到客户端上.

    原文为了在客户端上分别得到结果,所以用了 客户端激活模式.

  • 相关阅读:
    并查集图冲突hdu1272
    CentOS 7通过yum安装fcitx五笔输入法
    近期的技术问题让云供应商进行预设加密
    POJ 1166 The Clocks (暴搜)
    windows中的mysql修改管理员密码
    Visio画UML类图、序列图 for Java
    js中的时间与毫秒数互相转换
    java.lang.OutOfMemoryError: unable to create new native thread 居然是MQ问题
    WEB移动应用框架构想(转载)
    Android SDK安装教程
  • 原文地址:https://www.cnblogs.com/newsea/p/970433.html
Copyright © 2020-2023  润新知