Remoting的入门教程
注:<网摘自http://www.codesky.net/article/200411/48322.html>
基本原理
当客户端创建远程RemotableClass的一个实例,.NET框架在客户端应用程序域中产生一个代理。该代理看起来就像实际对象。代理收到调用后,通过通道连接到远程的对象。
一、编写步骤
第一步
编写一个DLL,其中包含所要Remottable的类
public class RemotableClass:MarshalByRefObject
{
….
}
第二步
服务器进程注册该remotable 类以便其他应用程序可以激活。根据该对象是如何激活,服务器通过两种静态方法来注册:RegisterActivatedServiceType或者RegisterWellKnownServiceType。下面的语句使用RegisterWellKnownServiceType来注册RemotableClass,以便远程激活。
RemotingConfiguration.RegisterWellKnownServiceType(
Typeof(RemotableClass), //Remotable类
"RemoteObject", // Remotable类的URI
WellKnownObjectMode.SingleCall); //激活模式
第一个参数是指能远程化的类。
第二个是指客户端使用来激活对象的URI----也就是客户端告诉服务器来激活
RemotableClass实例的URI。
第三个参数指定激活模式。有两种选择。WellKnownObjectMode.SingleCall是指为客户端的每一次调用创建一个新的实例。WellKnownObjectMode.Singleton是指创建一个RemotableClass实例来处理所有客户端的调用。
第三步
为了使客户端可以使用RemotableClass,服务器进程必须创建,注册一个通道。该通道提供对象和远程客户端交流的一个渠道。在服务器端,.NET框架提供了两种通道:
System.Runtime.Remoting.Channels.Tcp.TcpServerChannel:可以接受远程客户端的TCP连接。
System.Runtime.Remoting.Channels.Http.HttpServerChannel:接受HTTP连接。
下面的语句创建一个在1234端口监听的TcpServerChannel通道,并用.NET框架注册:
TcpServerChannel channel = new TcpServerChannel(1234);
ChannelServices.RegisterChannel(channel);
下面的语句注册了一个在1234端口监听的HTTP通道:
HttpServiceChannel channel = new HttpServerChannel(1234);
ChannelServices.RegisterChannel(channel);
TcpServerChannel更有效率一点。HttpServerChannel是使用IIS作为远程激活代理时使用的选择。
第四步
在客户端要想创建远程类的一个实例,也必须做一些注册。
第一必须注册一个客户端通道。.NET框架提供了两种类型的客户端通道:TcpClientChannel和HttpClientChannel,分别和服务器端通道相对应。
第二,如果客户端想使用new操作符来生产远程对象,必须将远程对象注册到本地应用程序域。
RemotingConfiguration.RegisterWellKnownClientType是在客户端注册一个类。
RemotingConfiguration.RegisterWellKnownServiceType是在服务器上注册一个类。
下面的代码在客户端注册了一个TCP通道,而且也将RemotableClass注册到本地应用程序域中:
TcpClientChannel channel = new TcpClientChannel();
ChannelServices.RegisterChannel(channel);
RemotingConfiguration.RegisterWellKnownClientType( Typeof(RemotableClass), "tcp://localhost:1234/RemoteObject");
第二个参数是指远程对象的URL。
协议必须匹配应用程序注册的通道协议。
可以使用机器名或者IP地址来替换localhost。
端口数必须好服务器端监听的端口数一样。
对象URI,必须和服务器用RegisterWellKnownServiceType注册的匹配。
第五步
在客户端使用new来产生代理:
RemotableClass rc = new RemotableClass();
这个操作在客户端应用程序域中产生一个代理,返回RemotableClass的一个引用。
二、实际范例
ClockServer.cs
using System;
public class Clock : MarshalByRefObject
{
public string GetCurrentTime ()
{
return DateTime.Now.ToLongTimeString ();
}
}
TimeServer.cs
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
class MyApp
{
static void Main ()
{
TcpServerChannel channel = new TcpServerChannel (1234);
ChannelServices.RegisterChannel (channel);
RemotingConfiguration.RegisterWellKnownServiceType(typeof (Clock), "Clock", WellKnownObjectMode.SingleCall);
Console.WriteLine ("Press Enter to terminate...");
Console.ReadLine ();
}
}
TimeClient.cs
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
class MyApp
{
static void Main ()
{
TcpClientChannel channel = new TcpClientChannel ();
ChannelServices.RegisterChannel (channel);
RemotingConfiguration.RegisterWellKnownClientType(typeof (Clock), "tcp://localhost:1234/Clock");
Clock clock = new Clock ();
Console.WriteLine (clock.GetCurrentTime ());
}
}
编译:
1. csc /t:library clockserver.cs
2. csc /r:clockserver.dll timeserver.cs
3. csc /r:clockserver.dll timeclient.cs
要将ClockServer.dll拷贝到客户端。因为创建远程对象的代理时,.NET框架需要描述Clock类的原数据。它可以从DLL中得到原数据。
三、配置方式
TimeServer和TimeClient在其源代码内部注册通道和远程化的类。这样有个缺点,一旦任何一个注册数据改变,你必须要修改源代码,并重新编译。
这就是为什么.NET框架支持另一种形式的注册。声明注册是通过调用静态
RemotingConfiguration.Configure方法来从Config文件中得到信息。
范例如下:
ClockServer.cs
using System;
public class Clock : MarshalByRefObject
{
public string GetCurrentTime ()
{
return DateTime.Now.ToLongTimeString ();
}
}
TimeServer.cs
using System;
using System.Runtime.Remoting;
class MyApp
{
static void Main ()
{
RemotingConfiguration.Configure ("TimeServer.exe.config");
Console.WriteLine ("Press Enter to terminate...");
Console.ReadLine ();
}
}
TimeServer.exe.config
<configuration>
<system.runtime.remoting>
<application>
<service>
<wellknown mode="SingleCall" type="Clock, ClockServer" objectUri="Clock" />
</service>
<channels>
<channel ref="tcp server" port="1234" />
</channels>
</application>
</system.runtime.remoting>
</configuration>
TimeClient.cs
using System;
using System.Runtime.Remoting;
class MyApp
{
static void Main ()
{
RemotingConfiguration.Configure ("TimeClient.exe.config");
Clock clock = new Clock ();
Console.WriteLine (clock.GetCurrentTime ());
}
}
TimeClient.exe.config
<configuration>
<system.runtime.remoting>
<application>
<client>
<wellknown type="Clock, ClockServer" url="tcp://localhost:1234/Clock" />
</client>
<channels>
<channel ref="tcp client" />
</channels>
</application>
</system.runtime.remoting>
</configuration>
该方式的缺点是配置文件可以被修改和删除。
四、激活方式
.NET框架将可远程化对象分为两种:服务器激活对象和客户端激活对象。服务器端激活对象是通过RemotingConfiguration’sRegisterWellKnownServiceType和
RegisterWellKnownClientType方法注册的。上面的范例都是服务器端激活对象。客户端激活对象是通过RegisterActivateServiceType和RegisterActivatedClientType注册的。
服务器端激活对象被称为服务器激活的,因为当客户端使用new,只有一个代理被创建。实际对象知道通过代理来调用一个方法时才被创建(激活)。换句话说,不是客户端决定什么时候去创建物理上的真正对象。客户端激活对象在客户端使用new时就在服务器上创建。这个是第一个差别。
第二个差别是客户端激活对象可以使用非缺省构造函数(带参数的构造函数)激活。服务器端机会对象不支持非缺省构造函数,因为使用new只是创建一个代理,并没有创建对应的实际对象。客户端激活对象可以通过new同时创建代理和对象。
第三个差别是客户端和对象是如何联系在一起的。当注册服务器激活对象时,你可以指定激活模式来决定为每一个请求创建一个对象实例还是创建一个对象实例来服务所有的请求。这两中激活模式是:
WellKnownObjectMode.SingleCall:为每个请求创建一个唯一的对象实例。
WellKonwnObjectMode.Singleton:创建一个对象实例来服务所有的请求
通常根据环境来选择合适的激活模式。举例来说,如果一个远程化对象提供了一个"One-shot"服务,不需要在多次调用间保持状态或者不需要在所有客户端同享状态,那么SingleCall是个正确的选择。因为每一次的请求产生的是一个新的对象实例。如果想在客户端之间传递数据,则要使用Singleton。
Singleton对象一个值得注意的地方是线程的同步问题。当两个客户端同时调用该对象的方法时,可能会出现错误,这时要使用.NET框架提供的同步机制。
客户端激活对象提供第三种选择。当使用客户端激活对象时,该对象仅为此客户端服务,可以在多次调用间保持状态。
Single-call服务器激活对象,Singleton服务器激活对象和客户端激活对象的提供了三种不同的激活模式。当不需要在所有客户端共享状态时,则使用Single-call。当要在所有客户端共享状态时则使用Singleton。当不需要所有的客户端连接到同一个对象,只要保持该客户端自己的状态时,则使用客户端激活对象。
程序范例:
Stopwatch.cs
using System;
public class Stopwatch : MarshalByRefObject
{
DateTime mark = DateTime.Now;
public void Start ()
{
mark = DateTime.Now;
}
public int Stop ()
{
return (int) ((DateTime.Now - mark).TotalMilliseconds);
}
}
StopwatchServer.cs
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
class MyApp
{
static void Main ()
{
TcpServerChannel channel = new TcpServerChannel (1234);
ChannelServices.RegisterChannel (channel);
RemotingConfiguration.RegisterActivatedServiceType(typeof (Stopwatch));
Console.WriteLine ("Press Enter to terminate...");
Console.ReadLine ();
}
}
StopwatchClient.cs
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
class MyApp
{
static void Main ()
{
TcpClientChannel channel = new TcpClientChannel ();
ChannelServices.RegisterChannel (channel);
RemotingConfiguration.RegisterActivatedClientType(typeof (Stopwatch), "tcp://localhost:1234");
Stopwatch sw = new Stopwatch ();
sw.Start ();
Console.WriteLine ("Press Enter to show elapsed time...");
Console.ReadLine ();
Console.WriteLine (sw.Stop () + " millseconds");
}
}
五、Activator.GetObject和Activator.CreateInstance方法
new操作符并不是激活远程对象的唯一方法。.NET框架提供了其他的激活方法:GetObject和CreateInstance。它们都是System.Activator类的成员。GetObject被用来激活在服务器端激活的对象,而CreateInstance被用来激活在客户端激活的对象。
当使用GetObject或者CreateInstance来激活远程对象时,不再需要调用RegisterActivatedClientType或者RegisterWellKnownClientType来注册服务器上可远程化的类。例如:激活在服务器端激活的对象时:
RemotingConfiguration.RegisterWellKnownClientType(typeof(Clock),"tcp://localhost:1234/Clock");
Clock clock = new Clock();
可以使用下面的方法代
Clock clock =(Clock) Activator.GetObject(typeof(Clock,"tcp://localhost:1234/Clock");
激活客户端对象时:
RemotingConfiguration.RegisterActivatedClientType(typeof(Stopwatch),"tcp://localhost:1234");
Stopwatch sw = new StopWatch();
可以这样的方式:
object[] url ={new UrlAttribute("tcp://localhost:1234")};
Stopwatch sw =(Stopwatch) Activator.CreateInstance(typeof(Stopwatch),null,url);
为什么要使用它们来代替new呢?因为在你仅知道URL和接口时,GetObject和CreateInstance可以仍使用。假设改变Clock类,它实现一个IClock接口。
使用GetObject时:
Iclock ic = (Iclock)Activator.GetObject(typeof(Iclock),"tcp://localhost:1234/Clock");
如果使用new,则会出现编译错误,因为new不能接受一个接口名称:
RemotingConfiguration.RegisterWellKnownClientType(typeof (IClock), "tcp://localhost:1234/Clock");
IClock ic = new IClock ();
六、对象生存期和租用期
一个single-call服务器端激活对象只在方法调用期间生存。之后,被垃圾回收器标记为删除。Singleton 服务器激活对象和客户端激活对象不一样,他们的生存期被租用控制。租用是一个对象,它实现了定义在System.Runtime.Remoting.Lifetime名称空间的Ilease接口。
Singleton 服务器端激活对象和客户端激活对象缺省的租用对象有一个5分钟的InitialLeaseTime,2分钟的RenewOnCallTime,5分钟的CurrentLeaseTime。如果对象没有方法被调用,当CurrentLeaseTime为0时它被清除,也就是5分钟后被清除。
Remoting的入门教程的更多相关文章
- 【WCF】无废话WCF入门教程
一.概述 Windows Communication Foundation(WCF)是由微软发展的一组数据通信的应用程序开发接口,可以翻译为Windows通讯接口,它是.NET框架的一部分.由 .NE ...
- 无废话WCF入门教程一[什么是WCF]
http://www.cnblogs.com/iamlilinfeng/archive/2012/09/25/2700049.html wcf技术交流,同学习共进步,欢迎加群: 群号:3981831 ...
- WCF入门教程一[什么是WCF]
一.概述 Windows Communication Foundation(WCF)是由微软发展的一组数据通信的应用程序开发接口,可以翻译为Windows通讯接口,它是.NET框架的一部分.由 .NE ...
- WCF入门教程一[什么是WCF]--转载只为学习收藏
一.概述 Windows Communication Foundation(WCF)是由微软发展的一组数据通信的应用程序开发接口,可以翻译为Windows通讯接口,它是.NET框架的一部分.由 .NE ...
- WCF入门教程[WCF基本应用]
一.概述 Windows Communication Foundation(WCF)是由微软发展的一组数据通信的应用程序开发接口,可以翻译为Windows通讯接口,它是.NET框架的一部分.由 .NE ...
- WCF入门教程系列一
一.概述 Windows Communication Foundation(WCF)是由微软发展的一组数据通信的应用程序开发接口,可以翻译为Windows通讯接口,它是.NET框架的一部分.由 .NE ...
- WCF入门教程(四)通过Host代码方式来承载服务 一个WCF使用TCP协议进行通协的例子 jquery ajax调用WCF,采用System.ServiceModel.WebHttpBinding System.ServiceModel.WSHttpBinding协议 学习WCF笔记之二 无废话WCF入门教程一[什么是WCF]
WCF入门教程(四)通过Host代码方式来承载服务 Posted on 2014-05-15 13:03 停留的风 阅读(7681) 评论(0) 编辑 收藏 WCF入门教程(四)通过Host代码方式来 ...
- 【转】WCF入门教程一[什么是WCF]
一.概述 Windows Communication Foundation(WCF)是由微软发展的一组数据通信的应用程序开发接口,可以翻译为Windows通讯接口,它是.NET框架的一部分.由 .NE ...
- powershell入门教程-v0.3版
powershell入门教程-v0.3版 来源 https://www.itsvse.com/thread-3650-1-1.html 参考 http://www.cnblogs.com/piapia ...
随机推荐
- MyBatis中井号与美元符号的区别
#{变量名}可以进行预编译.类型匹配等操作,#{变量名}会转化为jdbc的类型. select * from tablename where id = #{id} 假设id的值为12,其中如果数据库字 ...
- MVC神韵---你想在哪解脱!(十三)
维护模型与数据库结构之间的差别 现在我们已经将应用程序修改完毕,在Movie数据模型中添加了一个Rating属性.现在让我们重新运行应用程序,打开“http://localhost:xx/Movies ...
- Proactor设计模式:单线程高并发
Boost::Asio为同步和异步操作提供了并行支持,异步支持基于前摄器模式,这种模式的优点和缺点可能比只同步或反应器方法要低. 让我们检查一下Boost::Asio是如何实现前摄器模式的,没有引用基 ...
- Volley使用指南第四回(来自developer.android)
Volley网络请求的第四篇,废话不多说,开始. 这一篇文章将会教你怎样在Volley支持的范围内定制一个请求. 第一步:写一个通用请求: 大多数请求都有已经写好的接口供你调用,如果你的请求是Stri ...
- Hadoop之父Doug Cutting
生活中,可能所有人都间接用过他的作品,他是Lucene.Nutch .Hadoop等项目的发起人.是他,把高深莫测的搜索技术形成产品,贡献给普罗大众:还是他,打造了目前在云计算和大数据领域里如日中天的 ...
- Codeforces Round #278 (Div. 1) A. Fight the Monster 暴力
A. Fight the Monster Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/487/ ...
- iOS开发——数据持久化&使用NSUserDefaults来进行本地数据存储
使用NSUserDefaults来进行本地数据存储 NSUserDefaults适合存储轻量级的本地客户端数据,比如记住密码功能,要保存一个系统的用户名.密码.使用NSUserDefaults是首 ...
- MySQL锁系列1
http://www.cnblogs.com/xpchild/p/3782311.html MySQL的锁:MySQL内部有很多种类的锁,按照用途不同,可以分为两类:1. 保护内存结构的锁,实现同 ...
- debian分区方案(就这个看着靠谱点)转
debian分区方案(就这个看着靠谱点)转 桌面系统/tmp 1G (仅用作临时文件) ext3/ext4/home Max (用户目录数据) ext3/ext4/usr 20G (软件) ext3/ ...
- php中如何使用phpredis
安装redis服务:下载地址:http://redis.io/download,下载最新文档版本.本教程使用的最新文档版本为 2.8.17,下载并安装: $ wget http://download. ...