.Net组件程序设计之远程调用(二)
激活模式
引用封送对象激活类型两种,
一种是客户端激活类型,一种是服务器端激活.
客户端激活对象
客户端激活方式:当客户端创建一个远程对象时,客户端得到的是一个新的实例引用,新的实例可以在内存中维持状态,并且可以使用参数化构造函数来激活远程对象。
服务器激活模式single-call
SingleCall激活方式:当客户端使用一个服务器激活方式为SingleCall的对象时,.NET为每个方法调用创建一个新对象,在方法执行完毕后,对象则被销毁,客户端虽然维持着对远程对象的引用,但是真实对象已经被销毁了。
服务器激活Singleton
Singleton激活方式:所有客户端共享一个远程对象。
下面为大家演示几段示例,就详细的清楚每一种激活方式的作用了。
服务端代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
1
using
System.Runtime.Remoting;
2
using
System.Runtime.Remoting.Messaging;
3
namespace
RemoteServer
4
/// <summary>
5
/// 服务端
6
/// </summary>
7
public
class
MyClass : MarshalByRefObject
8 {
9
public
MyClass()
10 {
11 _count++;
12
string
mes = AppDomain.CurrentDomain.FriendlyName;
13 Console.WriteLine(mes);
14 }
15
16
private
int
_count = 0;
17
18
public
event
EventHandler NumberChanged;
19
20
public
void
Count()
21 {
22 _count++;
23 Console.WriteLine(AppDomain.CurrentDomain.FriendlyName +
"_"
+ _count.ToString());
24 }
25
26
public
void
OnNumberChanged(
int
num)
27 {
28
if
(NumberChanged !=
null
)
29 {
30 NumberChanged(num,
null
);
31 }
32 }
33 }
34
35
public
class
EventMehtodClass : MarshalByRefObject
36 {
37 [OneWay]
38
public
void
OnNumberChanged(
object
sender, EventArgs e)
39 {
40
if
(sender !=
null
)
41 {
42 Console.WriteLine(sender.ToString());
43 }
44 }
45 }
|
2.编程式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
1 宿主服务端(服务器端)
2
using
System.Runtime.Remoting;
3
using
System.Runtime.Remoting.Channels;
4
using
System.Runtime.Remoting.Channels.Http;
5
using
System.Runtime.Remoting.Channels.Tcp;
6
using
System.Runtime.Remoting.Channels.Ipc;
7
using
System.Runtime.Remoting.Services;
8
using
RemoteServer;
9
10
namespace
RemoteServerHost
11
12 #region 编程式 宿主服务端注册 信道和对象类型
13 Console.WriteLine(
"开始Tcp注册信道"
);
14 IChannel tcpChannel =
new
TcpChannel(8003);
15 ChannelServices.RegisterChannel(tcpChannel,
false
);
//注册Tcp类型信道
16 Console.WriteLine(
"Tcp信道注册完成————————————————"
);
17 Console.WriteLine(
"开始 服务器激活类型SingleCall模式的宿主服务器端类型注册"
);
18 RemotingConfiguration.RegisterWellKnownServiceType(
typeof
(MyClass),
"RWCTmyclass"
,WellKnownObjectMode.SingleCall);
19 Console.WriteLine(
"类型注册完成"
);
20 #endregion
21
22 Thread.Sleep(
new
TimeSpan(0, 2, 0));
23 Console.WriteLine(
"释放Tcp信道"
);
24 ChannelServices.UnregisterChannel(tcpChannel);
|
这里所用的激活方式是 服务器SingleCall激活方式,通过RemotingConfiguration.RegisterWellKnownServiceType()方法来注册类型,第二个参数为统一资源标识符(URI),很好理解就是字面的意思,远程对象就是资源,标识资源的一个符号(名称),有了它,客户端在调用远程对象的时候才知道具体在哪。因为是服务器激活方式所以URI是在包含在注册类型的方法中的,而如果是客户端激活类型注册的话,则使用RemotingConfiguration.RegisterActivatedServiceType(typeof(MyClass));
有的朋友会问了,这样统一资源标识符不是没设置吗?是的,确实没有设置,客户端激活类型注册的时候URI是这样设置
1
|
1 RemotingConfiguration.ApplicationName =
"RWCTmyclass"
;
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
1 客户端(调用端)
2
using
System.Runtime.Remoting;
3
using
System.Runtime.Remoting.Channels;
4
using
System.Runtime.Remoting.Channels.Http;
5
using
System.Runtime.Remoting.Channels.Tcp;
6
using
System.Runtime.Remoting.Channels.Ipc;
7
using
System.Runtime.Remoting.Services;
8
using
RemoteServer;
9
10
namespace
RemoteClient
11
12 #region 编程式本地注册
13 Thread.Sleep(
new
TimeSpan(0, 0, 7));
//便于调,使当前客户端线程阻塞7秒,确保宿主服务端已经运行
14
string
url =
"tcp://localhost:8003/RWCTmyclass"
;
15 Console.WriteLine(
"开始客户端注册类型"
);
16 RemotingConfiguration.RegisterWellKnownClientType(
typeof
(MyClass), url);
17 #endregion
18
19
20
//类型使用
21 MyClass myclass =
new
MyClass();
22 myclass.Count();
23 MyClass myclass1 =
new
MyClass();
24 myclass1.Count();
图 1
|
因为这里使用的是服务器SingleCall类型模式激活的,所以对象状态是不保存的,就跟上面那一小节定义的一样,只有在方法调用的时候才会被创建,方法调用完毕则会被释放销毁,但是也可以在宿主服务端使用变量来记录状态。现在可以在宿主服务端(服务器端)注册类型的时候把激活模式换成Singleton的再来看一下结果:
这是编程式的示例代码,下面给大家演示配置式的。
3.配置式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
1 宿主服务端(服务器端)
2
using
System.Runtime.Remoting;
3
using
System.Runtime.Remoting.Channels;
4
using
System.Runtime.Remoting.Channels.Http;
5
using
System.Runtime.Remoting.Channels.Tcp;
6
using
System.Runtime.Remoting.Channels.Ipc;
7
using
System.Runtime.Remoting.Services;
8
9
using
System.Threading;
10
11
using
RemoteServer;
12
13
namespace
RemoteServerHost
14
15 #region 配置式宿主服务端注册 信道和对象类型
16 Console.WriteLine(
"开始注册Http信道"
);
17 RemotingConfiguration.Configure(AppDomain.CurrentDomain.FriendlyName +
".config"
);
18 Console.WriteLine(
"Http信道注册完成————————————————"
);
19 #endregion
|
这里只要使用.NET给我们提供的RemotingConfiguration类型中的Configure()方法来加载配置文件就行了,注册信道的类型,远程对象的激活方式和模式都是在配置文件中注册的,来看配置文件信息:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
1 <?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
2 <
configuration
>
3 <
system.runtime.remoting
>
4 <
application
>
5 <
channels
>
6 <
channel
ref
=
"http"
port
=
"8004"
/>
7 </
channels
>
8 <
service
>
9 <
wellknown
mode
=
"Singleton"
type
=
"RemoteServer.MyClass,RemoteServer"
objectUri
=
"RTMyClass"
/>
10 </
service
>
11 </
application
>
12 </
system.runtime.remoting
>
13 </
configuration
>
|
这里配置文件中,是准备注册http类型的信道,并且把远程对象注册为服务器激活类型(wellKnow)Singleton激活模式,宿主服务端的就这么多,接下来看客户端的.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
1 客户端
2
using
System.Runtime.Remoting;
3
using
System.Runtime.Remoting.Channels;
4
using
System.Runtime.Remoting.Channels.Http;
5
using
System.Runtime.Remoting.Channels.Tcp;
6
using
System.Runtime.Remoting.Channels.Ipc;
7
using
System.Runtime.Remoting.Services;
8
9
using
System.Threading;
10
11
using
RemoteServer;
12
13
namespace
RemoteClient
14
15 #region 配置式本地注册
16 Thread.Sleep(
new
TimeSpan(0, 0, 7));
17 Console.WriteLine(
"开始客户端注册类型"
);
18 RemotingConfiguration.Configure(AppDomain.CurrentDomain.FriendlyName +
".config"
,
false
);
19 #endregion
20
//类型使用
21 Console.WriteLine(AppDomain.CurrentDomain.FriendlyName);
22 MyClass myclass =
new
MyClass();
23 myclass.Count();
24 MyClass myclass1 =
new
MyClass();
25 myclass1.Count();
|
跟宿主服务端的一样,使用Configure()方法来注册远程对象,但是本地的配置文件怎么配置呢?不着急的,一起来看:
1
2
3
4
5
6
7
8
9
10
|
1 <?xml version=
"1.0"
encoding=
"utf-8"
?>
2 <configuration>
3 <system.runtime.remoting>
4 <application>
5 <client>
6 <wellknown type=
"RemoteServer.MyClass,RemoteServer"
url=
"http://localhost:8004/RTMyClass"
/>
7 </client>
8 </application>
9 </system.runtime.remoting>
10 </configuration>
|
客户端 要注册的 远程对象类型 的 激活类型(客户端激活、服务器端激活) 是要跟宿主服务端的相对应。
这次换了Singleton模式
图2
4.远程回调
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
1 宿主服务端:
2
using
System.Runtime.Remoting;
3
using
System.Runtime.Remoting.Channels;
4
using
System.Runtime.Remoting.Channels.Http;
5
using
System.Runtime.Remoting.Channels.Tcp;
6
using
System.Runtime.Remoting.Channels.Ipc;
7
using
System.Runtime.Remoting.Services;
8
using
System.Threading;
9
10
using
RemoteServer;
11
namespace
RemoteServerHost
12
13
14 #region 远程回调
15 Console.WriteLine(
"开始Tcp注册信道"
);
16 BinaryServerFormatterSinkProvider formatter =
new
BinaryServerFormatterSinkProvider();
//二进制格式化器
17 formatter.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
//设置过滤类型为Full
18
19 IDictionary channel =
new
Hashtable();
20 channel[
"name"
] =
"RWCTmyclass"
;
21 channel[
"port"
] = 8003;
22
23 IChannel tcpChannel =
new
TcpChannel(channel,
null
, formatter);
24 ChannelServices.RegisterChannel(tcpChannel,
false
);
//注册Tcp类型信道
25 Console.WriteLine(
"Tcp信道注册完成————————————————"
);
26 Console.WriteLine(
"开始 服务器激活类型Singleleton模式的宿主服务器端类型注册"
);
27 RemotingConfiguration.RegisterWellKnownServiceType(
typeof
(MyClass),
"RWCTmyclass"
, WellKnownObjectMode.Singleton);
28 Console.WriteLine(
"类型注册完成"
);
29 #endregion
30
31
32 Thread.Sleep(
new
TimeSpan(0, 2, 0));
33
34 Console.WriteLine(
"释放Tcp信道"
);
35 ChannelServices.UnregisterChannel(tcpChannel);
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
1 客户端:
2
3
using
System.Runtime.Remoting;
4
using
System.Runtime.Remoting.Channels;
5
using
System.Runtime.Remoting.Channels.Http;
6
using
System.Runtime.Remoting.Channels.Tcp;
7
using
System.Runtime.Remoting.Channels.Ipc;
8
using
System.Runtime.Remoting.Services;
9
10
using
System.Threading;
11
12
using
RemoteServer;
13
14
namespace
RemoteClient
15
16
17 #region 远程回调
18 Thread.Sleep(
new
TimeSpan(0, 0, 7));
19 IChannel tcp =
new
TcpChannel(0);
20 ChannelServices.RegisterChannel(tcp,
false
);
21
string
url =
"tcp://localhost:8003/RWCTmyclass"
;
22 Console.WriteLine(
"开始客户端注册类型"
);
23 RemotingConfiguration.RegisterWellKnownClientType(
typeof
(MyClass), url);
24 #endregion
25
26 Console.WriteLine(AppDomain.CurrentDomain.FriendlyName);
27 MyClass myclass =
new
MyClass();
28 myclass.Count();
29 EventMehtodClass methodclass =
new
EventMehtodClass();
30 myclass.NumberChanged += methodclass.OnNumberChanged;
31 Thread.Sleep(100);
32 myclass.OnNumberChanged(100);
|
图-3
在Singleton激活方式下是可以完成远程回调的,但是用Singlecall模式的话则不行,因为如果是这样的话,之前对远程对象(服务器对象)的操作都没有状态保存,上面说到过,Singlecall模式是一来一回则被释放掉了,本地客户端仅仅是保留了一个代理。可以验证一下:
修改宿主服务端的代码Singleton改为SingleCall
1
|
1 RemotingConfiguration.RegisterWellKnownServiceType(
typeof
(MyClass),
"RWCTmyclass"
, WellKnownObjectMode.SingleCall);
|
修改客户端的代码 myclass.Count();又新加一句
1
2
3
4
5
6
7
|
1 MyClass myclass =
new
MyClass();
2 myclass.Count();
3 myclass.Count();
4 EventMehtodClass methodclass =
new
EventMehtodClass();
5 myclass.NumberChanged += methodclass.OnNumberChanged;
6 Thread.Sleep(100);
7 myclass.OnNumberChanged(100);
|
修改后的运行结果:
图4
为什么没有像图1中的那样发生回调这里已经不用说明了。
本文转自jinyuan0829 51CTO博客,原文链接:http://blog.51cto.com/jinyuan/1422434,如需转载请自行联系原作者