remoting教学二:remoting的激活
远程对象的激活分两类,服务器端激活和客户端激活。所谓激活即所谓new一个远程对象的实例。激活模式的不同,区别在于远程对象是否有状态和激活的时间及点。下面具体阐述:
1:服务器端激活
服务器端激活有两种方式SingleCall和Singleton。
我们注意到第一章中,服务器端代码中有一段为:
RemotingConfiguration.RegisterWellKnownServiceType(typeof(RemoteObject.MyObject),
"RemoteObject", WellKnownObjectMode.SingleCall);
这里便是注册服务器端激活的模式。先来看这两种模式的一点区别:
如果SERVER端用SingleCall模式,则无论打开多少个客户端,i都是等于1的。也就是,server为每一个客户端都创建了一个RemoteObject对象(更具体的说是为每一次客户端调用)。
若我们改为Singleton,则发现每打开一个客户端,i的值就+1,即不管连接多少个客户端,服务器只保留一个remoteObject对象。
2:客户端激活
客户端激活的时间是在客户端请求的时候,而服务端激活远程对象的时间是在调用对象方法的时候。客户端激活模式一旦获得客户端的请求,将为每一个客户端都建立一个实例引用。这点并不同于服务器端激活的SingleCall。SingleCall是为每一次客户端调用都创建远程对象,而客户端激活是,在一个会话生存期内,不管发起多少次调用,都只为每个客户端生成一个远程对象。
3:远程对象状态
这里要明确一个概念“有状态对象”和“无状态对象状态”。服务器端激活的SingleCall,每次调用都会新建对象,因此对象是无状态的。服务器端激活的Singleton,对象只被创建一次,所有客户共享对象状态,因此对象是有状态的。客户端激活对象使用类的类型来激活,uri在后台被动态创建,并且返回给客户程序。客户激活对象是有状态的。
以表格方式列明区别如下:
激活方式 | 模式 | 几个实例 | 有状态否 |
服务器端 | SingleCall | 一次客户端调用一个实例 | 无 |
服务器端 | Singleton | 所有客户端共用实例 | 有 |
客户端 | | 一个客户端一个实例 | 有 |
4:编码实现:
我个人习惯在代码中实现配置,这样可以让思路更清晰。除了在代码进行激活模式的注册外,还可以在配置文件中进行。
4.1 SingleCall:
服务器端代码:
TcpServerChannel channel = new TcpServerChannel(9999);
ChannelServices.RegisterChannel(channel);
RemotingConfiguration.RegisterWellKnownServiceType(
typeof(RemoteObject.MyObject),
"RemoteObject", WellKnownObjectMode.SingleCall);
客户端代码:
ChannelServices.RegisterChannel(new TcpClientChannel());
RemoteObject.MyObject remoteobj = (RemoteObject.MyObject)Activator.GetObject(typeof(RemoteObject.MyObject), "tcp://localhost:9999/RemoteObject");
远程对象类可以扩展MarshalByRefObject,也可以使用[Serializable]
4.2 Sington:
服务器端代码:
TcpServerChannel channel = new TcpServerChannel(9999);
ChannelServices.RegisterChannel(channel);
RemotingConfiguration.RegisterWellKnownServiceType(
typeof(RemoteObject.MyObject),
"RemoteObject", WellKnownObjectMode.Singleton);
客户端代码:
ChannelServices.RegisterChannel(new TcpClientChannel());
RemoteObject.MyObject remoteobj = (RemoteObject.MyObject)Activator.GetObject(typeof(RemoteObject.MyObject),
"tcp://localhost:9999/RemoteObject");
对于Sington模式来说,另一类写法。
服务器端代码:
BinaryClientFormatterSinkProvider binaryClient = new BinaryClientFormatterSinkProvider();
BinaryServerFormatterSinkProvider provider = new BinaryServerFormatterSinkProvider();
provider.TypeFilterLevel = TypeFilterLevel.Full;
IDictionary props = new Hashtable();
props["name"] = "tcp";
props["port"] = 9999;
TcpChannel chan = new TcpChannel(props, binaryClient, provider);
ChannelServices.RegisterChannel(chan,false);
ob = new MyObject();
ObjRef obj = RemotingServices.Marshal(ob, "ServiceMessage");
客户端代码:
BinaryClientFormatterSinkProvider binaryClient = new BinaryClientFormatterSinkProvider();
BinaryServerFormatterSinkProvider binaryServer = new BinaryServerFormatterSinkProvider();
binaryServer.TypeFilterLevel = TypeFilterLevel.Full;
IDictionary diction = new Hashtable();
bool isExist = false;
diction["name"] = "tcp";
diction["port"] = 0;
TcpChannel tcp = new TcpChannel(diction, binaryClient, binaryServer);
ChannelServices.RegisterChannel(tcp,false);
remoteobj = (RemoteObject.MyObject)Activator.GetObject(typeof(RemoteObject.MyObject),
"tcp://localhost:9999/ServiceMessage");
远程对象类必须扩展MarshalByRefObject,而不是使用[Serializable]属性标识。
4.3 客户端激活:
服务器端代码:
TcpServerChannel channel = new TcpServerChannel(9999);
ChannelServices.RegisterChannel(channel);
RemotingConfiguration.RegisterActivatedServiceType(
typeof(RemoteObject.MyObject));
客户端代码:
RemoteObject.MyObject app = (RemoteObject.MyObject)Activator.CreateInstance(typeof(RemoteObject.MyObject)
, null, new object[] {
new System.Runtime.Remoting.Activation.UrlAttribute("tcp://localhost:9999/") });
远程对象类扩展MarshalByRefObject,而不是使用[Serializable]