现在的位置: 首页 > 综合 > 正文

关于Remoting

2013年10月05日 ⁄ 综合 ⁄ 共 3805字 ⁄ 字号 评论关闭

这几天看了不少Remoting文章。明白了不少技术细节,但困惑也不少。简单说来,Remoting是一个分布式处理服务。服务器端首先创建通道(Channel),并自动开启监听通道。根据客户端发出的请求,传递远程对象。

因此,编写Remoting程序,主要分为三部分:
1、被传递的远程对象;
2、服务器端监听程序;
3、客户端请求和处理对象程序;

一、被传递的远程对象
在Remoting中,被传递的远程对象类是有诸多限制的。首先,我们必须清楚,这里所谓的传递是以引用的方式,因此所传递的远程对象类必须继承MarshalByRefObject。MarshalByRefObject 是那些通过使用代理交换消息来跨越应用程序域边界进行通信的对象的基类。不是从 MarshalByRefObject 继承的对象会以隐式方式按值封送。当远程应用程序引用一个按值封送的对象时,将跨越远程处理边界传递该对象的副本。因为您希望使用代理方法而不是副本方法进行通信,因此需要继承 MarshallByRefObject。(MSDN)

public class ServerObject:MarshalByRefObject
    
{
        
public Person GetPersonInfo(string name,string sex,int age)
        
{
            Person person 
= new Person();
            person.Name 
= name;
            person.Sex 
= sex;
            person.Age 
= age;
            
return person;
        }

    }

这个类只实现了最简单的方法,就是设置一个人的基本信息,并返回一个Person类对象。值得注意的是,这里返回的Person类。由于是以引用和远程调用的方式。这里所传递的Person则是以传值的方式来完成。因此必须涉及到一个序列化的问题。

所以,Remoting要求对象类还要调用或传递某个对象,例如类,或者结构,则该类或结构则必须实现串行化Attribute。[Serializable]。

[Serializable]
    
public class Person
    
{
        
public Person()
        
{
            
        }


        
private string name;
        
private string sex;
        
private int age;

        
public string Name
        
{
            
get    {return name;}
            
set    {name = value;}
        }


        
public string Sex
        
{
            
get {return sex;}
            
set {sex = value;}
        }


        
public int Age
        
{
            
get {return age;}
            
set {age = value;}
        }

    }

这个服务器对象,以类库的方式编译成Dll,这个工作就算完成了。

那么这个对象是怎么实现被客户端和服务器端调用的呢?这就是下面我们必须要做的工作:将编译后的DLL分别添加到服务器端和客户端程序的引用中。也就是说,这个服务器对象Dll要拷贝两份,一份放在服务器端,一份放在客户端。为什么要这样?看了后面的代码就知道原因了。

如此一来,会有个问题存在。那就是代码的安全性。如果客户端必须要保持这个对象的Dll,则该对象的实现方式对于客户而言就近乎透明了。另外,这样对于部署也不好。两份同样的dll,如果传递的对象大,也会影响性能的。对于这个问题,我们可以使用接口来解决。显然,服务器端提供接口和具体类的实现,而客户端则只需要接口就可以了(不过,对于客户端激活模式则必须有实现接口的类)。

 

public interface IServerObject
    
{
        Person GetPersonInfo(
string name,string sex,int age);
    }


public class ServerObject:MarshalByRefObject,IServerObject

 

要注意的是:1、两边生成该对象程序集的名字必须相同,严格地说,是命名空间的名字必须相同。
                        2、这种方式根据激活方式的不同,实现也不同。如果是服务器端激活(SingleTon和SingCall),那很简单。如上所述的方法即可;

如果是客户端激活,最好是利用抽象工厂,提供创建实例的方法。下面的类图表描述了总体解决方案(MSDN)。

1:混合法的结构

这样就必须在代码中还要加上抽象工厂的接口及实现:

public interface IServerObjFactory
{
    IServerObject CreateInstance();
}


public class ServerObject:MarshalByRefObject,IServerObject,IServerObjFactory
{
   
public IServerObject CreateInstance()
   
{
       
return new ServerObject();
   }

}

但是由于客户端激活的方式,它必须调用类的构造函数来创建实例,因此,在客户端只实现接口似乎是不可能的。

说明:关于对象类继承MarshalByRefObject,我作过测试,使可以间接地继承的。也就是我们可以先通过实现基类来继承它。然后实际所传递的对象在从基类中派生。

最后的代码应该是这样(服务器端,如果是客户端,只需要接口即可。这里我加了抽象工厂,因此该对象应该是以客户端激活模式。如果是服务器端激活模式,应该把抽象工厂接口和实现方法去掉)

using System;

namespace ServerRemoteObject
{
    
    [Serializable]
    
public class Person
    
{
        
public Person()
        
{
            
        }


        
private string name;
        
private string sex;
        
private int age;

        
public string Name
        
{
            
get    {return name;}
            
set    {name = value;}
        }


        
public string Sex
        
{
            
get {return sex;}
            
set {sex = value;}
        }


        
public int Age
        
{
            
get {return age;}
            
set {age = value;}
        }

    }


    
public interface IServerObject
    
{
        Person GetPersonInfo(
string name,string sex,int age);
    }


    
public interface IServerObjFactory
    
{
        IServerObject CreateInstance();        
    }


    
public class ServerObject:MarshalByRefObject,IServerObject
    
{
        
public Person GetPersonInfo(string name,string sex,int age)
        
{
            Person person 
= new Person();
            person.Name 
= name;
            person.Sex 
= sex;
            person.Age 
= age;
            
return person;
        }
        
    }


    
public class ServerObjFactory:MarshalByRefObject,IServerObjFactory
    
{
        
public IServerObject CreateInstance()
        
{
            
return new

抱歉!评论已关闭.