.Net 3.5 Remoting编程入门二
.Net 3.5 Remoting编程入门二
什么是激活方式?
简单的理解:我们知道,在我们的Remoting应用需要远程处理对象,那么这些对象是怎么创建的?又是由谁去创建的呢?… 而激活方式则正是要说明这些疑问。
远程对象的激活方式分为:
服务器激活与客户端激活两种主要的方式,
其中服务器激活方式中又分为SingleCall(单调用)和Singleton(单例)。
当服务器激活模式为SingleCall时:
当每个客户端调用远程服务器上的对象时,服务端会为每个客户端产生一个对象供其使用,当客户端使用完毕后,此对象将被撤消。
当服务器激活模式为Singleton时:
当每个客户端调用远程服务器上的对象时,服务端仅客户端产生一个对象供其使用,当客户端使用完毕后,由对象并不被撤消,而是一直保持服务器端,以便其他客户端或下次调用。
客户端激活其用法和类似本地创建的对象。只是,客户端激活在一个单独的应用域中的宿主上运行,由起代理调用。
现在,我们在代码的基础上,学习各种激活方式。
首先,创建一个类Message.cs,这个类就是我们需要远程调用处理的类。这个类与第一章中的类是基本相同,我们现在只是增加了一个ID,方便我们后面的比较。
using System;
namespace RemotingClass
{
public class Message : MarshalByRefObject
{
public Guid MessageId { get; set; } //Guid,用于保存Message的ID
public Message()
{
this.MessageId = Guid.NewGuid();//当对象被实例同时产生一个ID
}
public delegate void MessageHandler(string msg);
public static event MessageHandler OnSendMessage;
public void SendMessage(string msg)
{
if (OnSendMessage != null)
OnSendMessage("Message的ID是:" + this.MessageId + msg);//为了看的清楚,把ID打印出来
}
}
}
服务端代码:使用Singleton激活
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
namespace Server
{
class Program
{
static void
{
Console.WriteLine("Host Started!");
HttpChannel channel = new HttpChannel(20001);
ChannelServices.RegisterChannel(channel,false);
RemotingConfiguration.RegisterWellKnownServiceType(typeof(RemotingClass.Message), "Message", WellKnownObjectMode.Singleton); //这里使用Singleton即代表使用服务端的Singleton激活方式
RemotingClass.Message.OnSendMessage += new RemotingClass.Message.MessageHandler(Message_OnSendMessage);
Console.Read();
}
public static void Message_OnSendMessage(string msg)
{
Console.WriteLine(msg);
}
}
}
客户端代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
namespace Client
{
class Program
{
static void
{
Console.WriteLine("Client Started!");
HttpChannel channel = new HttpChannel();
ChannelServices.RegisterChannel(channel, false);
RemotingConfiguration.RegisterWellKnownClientType(typeof(RemotingClass.Message), "http://localhost:20001/Message");//因采用的是服务端激活方式,所以客户端只需要注册对象类型和uri即可
RemotingClass.Message msg = new RemotingClass.Message();
while (true)
{
msg.SendMessage(" 现在是:" + System.DateTime.Now.ToString());
System.Threading.Thread.Sleep(2000);
}
//Console.ReadLine();
}
}
}
好了,代码编写完毕,然后编译运行,先运行服务端程序,再启动客户端程序,我们可以在服务端程序的界面看到,Message的ID每次都是一样的,说明,尽管客户端是每过2秒调用一次远程的对象,但是,每次调用都是同一个对象。
再来看看,服务器激活SingleCall方式。
只需要修改服务端程序的代码,如下:
RemotingConfiguration.RegisterWellKnownServiceType(typeof(RemotingClass.Message), "Message", WellKnownObjectMode.SingleCall); //只需要将这里由原来的Singleton换SingleCall即可
其他代码,远程类Message和客户端代码不需要修改。
然后编译运行,先运行服务端程序,再启动客户端程序,我们可以在服务端程序的界面看到,
Message的ID是每次都不一样的。说明,尽管客户端是每过2秒调用一次远程的对象,但是,每次调用都是都是一个全新的对象。
最后,我们来看看客户端激活方式。
第一步,远程处理的Message类不需要修改。
第二步,修改服务端程序,如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
namespace Server
{
class Program
{
static void
{
Console.WriteLine("Host Started!");
HttpChannel channel = new HttpChannel(20001);
ChannelServices.RegisterChannel(channel, false);
// RemotingConfiguration.RegisterWellKnownServiceType(typeof(RemotingClass.Message), "Message", WellKnownObjectMode.SingleCall); //这里使用SingleCall即可
RemotingConfiguration.RegisterActivatedServiceType(typeof(RemotingClass.Message));//注意这个地方与上面注释掉的代码是不同。采用客户端激活方式,服务端只需要对象类型即可。也就是告诉大家,来吧,这个类型可以远程调用
RemotingClass.Message.OnSendMessage += new RemotingClass.Message.MessageHandler(Message_OnSendMessage);
Console.Read();
}
public static void Message_OnSendMessage(string msg)
{
Console.WriteLine(msg);
}
}
}
第三步,修改客户端程序,如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
namespace Client
{
class Program
{
static void
{
Console.WriteLine("Client Started!");
HttpChannel channel = new HttpChannel();
ChannelServices.RegisterChannel(channel, false);
// RemotingConfiguration.RegisterWellKnownClientType(typeof(RemotingClass.Message), "http://localhost:20001/Message");
RemotingConfiguration.RegisterActivatedClientType(typeof(RemotingClass.Message), "http://localhost:20001");//现在由客户端来激活对象,所以它需要对象类型以及在服务端的url
RemotingClass.Message msg = new RemotingClass.Message();
while (true)
{
msg.SendMessage(" 现在是:" + System.DateTime.Now.ToString());
System.Threading.Thread.Sleep(2000);
}
//Console.ReadLine();
}
}
}
然后编译运行,先运行服务端程序,再启动客户端程序,我们可以在服务端程序的界面看到,
Message的ID没有变。因为客户端激活对象创建以后,可以多次调用。
那么什么时候采用客户端激活?什么时候采用服务器激活呢?
在客户端激活模式中,每个客户端都创建自己的对象,并能多次调用该对象。由于并发客户创建大量对象可能耗尽系统资源,所以这种模式的可扩展性不太好。如果预期的用户比较少,而且需要维护调用期间的状态信息时,可以考虑使用这个模式。
服务器激活方式可实现单例和单调用。
单例最适合在多用户之间共享一个资源或者协同操作,如聊天室。
如果客户端需要执行服务器上相对较短的操作,而且不需要为下一次调用保存状态信息,此时应可以使用单调用。这种方式最具有扩展性,而且能在利用负载平衡将调用指向对个服务器的环境中很好的工作。
以上代码是在VS2008 SP中C#3.0写的。
OK,就写到这里,明天要上班,后面我们在一起继续学习!