.net remoting学习(1)---remoting简单介绍与实现
window为了程序的安全,每个应用程序被划分为一个个进程。如果不通过例如RPC进程通信机制之类的方法就很难访问另外的进程。而.net remoting不仅提供了在本地两个.net程序之间互访问的能力,而且还允许远程调用从而建立分布式的应用程序。.net remoting提供了两种方式来传递消息对象,分别为序列化成二进制格式消息流和序列化成使用soap协议的消息流进行传输。这两种方式.net都已经提供了对应的tcp传输和http传输实现,他们都实现了名为IChannel的接口,这意味着您也可以自己实现消息的传输方式,只要能实现IChannel接口就可以了。
那么在.net remoting中是如何进行交换信息对象的呢,我从网上找了一个.net remoting的体系图(左下)来说明一下:从图中我们可以看出他的体系基本上可以分为两个部分,客户端和服务端,然后他们中间通过一个叫做Channel(通道)的东西来进行消息对象的传递。
我们这里以客户端调用服务端为例。如果客户端要想调用服务端的对象就必须先在他和服务器之间建立一个通道用来传递对象消息,这个通道可以是上面说的tcp通道或者http通道或者自定义通道中的一个。然后,客户端通过一个叫做代理的东西进行远程调用。有人或许会疑问了,那么这个代理到底是什么东西呢?这个代理简单一点可以看做成服务端的一个对象引用,即通过这个代理你就可以像在本地操作对象一样操作服务端的对象了。具体的代理操作方式我们在下面的代码部分介绍。
不得不说微软帮我们封装的真好,简单的几句话就进行了跨进程、分布式的应用。或许您对上面说的一时还有点稀里糊涂,没事,下面我们通过一个简单的例子来揭开.net remoting的神秘面纱,并以这个例子一步一步深入.net remoting的世界。准备好了吗?让我们开始吧!
先看一下右边的项目截图,使得我们对这个例子的结构有个总体的认识。
解决方案分为三个部分,大家看名字也知道了,分别对应客户端,服务端和一个公用的类库。客户端负责调用服务端的对象并取得返回的值,服务端则接受客户端发送的“请求”并处理。这个例子的最后结果应该是客户端调用客户端的Person类中的GetPersonInfo方法,并取得他的返回值显示出来。当然在服务端中我们也会显示出到底是哪个客户端调用了他的对象。
好了,先来看Common下的person类。因为客户端和服务端传递的对象都必须是双方都知道的,所以这个Person类必须被他们“识别”即引入在客户端和服务端分别引入这个类库就行了。这样当客户端通过代理操作本地的Person类时实际就会反映到服务端的Person类上面啦。
Common类:
public class Person : MarshalByRefObject { public Person() { } public int GetPersonInfo(int clientId) { Console.WriteLine(clientId + "号客户端调用服务端方法,服务器端返回值为:"+DateTime.Now.Second); return DateTime.Now.Second; } }
从上面可以看到Person类继承了MarshalByRefObject类,MSDN中对MarshalByRefObject是这样解释的:通过使用代理交换消息来跨应用程序域边界进行通讯的对象的基类。因为第一篇我想以一个简单的方式来呈现.net remoting,不想牵扯太多复杂的东西。MarshalByRefObject类后面的系列中会进行讲解。所以现在就请忘记它吧。
再来看服务端的代码:
class Program { static void Main(string[] args) { //注册tcp通道进行消息对象的传输 TcpChannel tcp = new TcpChannel(8085); //注册通道 ChannelServices.RegisterChannel(tcp,true); //将服务端的某个对象注册为已知类型,方便客户端调用 RemotingConfiguration.RegisterWellKnownServiceType ( typeof(Person), "SayHello", //服务端的标识,客户端调用的时候会用到这个 WellKnownObjectMode.Singleton ); System.Console.WriteLine("服务器正在等待信息,按任意键退出!"); System.Console.ReadLine(); } }
从最开始介绍.net remoting如何传递消息对象我们就讲到了,客户和服务端是通过成为通道的东西来进行传输的。所以在客户端和服务端我们都要进行通道的注册。从上面的代码我们可以看出来,通道的注册就两句话,很简单。当然我这里知识通过TcpChannel的方式进行传输的,您完全可以通过HttpChannel来进行。关于他们两种传输的区别,容我将所有的代码介绍完再进行介绍。
最后是客户端的代码:
class Program { static void Main(string[] args) { TcpChannel tcp = new TcpChannel(); //建立Tcp通道 ChannelServices.RegisterChannel(tcp,true); //注册tcp通道 //得到服务器端的对象代理,第二个 Person obj1 = (Person)Activator.GetObject( typeof(Person), "tcp://localhost:8085/SayHello"); //这里的端口号和SayHello都是服务端里面定义好的,不要写错了 if (obj1 == null) { System.Console.WriteLine( "连接TCP服务器失败"); } //通过代理调用服务端的方法 Console.WriteLine( "从服务器获得的返回值为:{0}", obj1.GetPersonInfo(new Random().Next(0,100))); Console.Read(); } }
注册通道的方式和服务端差不多,只不多他不需要指定端口号而已。之后的Activator.GetObject方法就相当于实现代理的部分啦,通过这个方法我们可以拿到服务端的Person对象引用并执行相应的操作。
来看看程序最后的运行结果吧,首先启动服务端程序,然后打开几个客户端程序。如我们所期望的一样,服务端和客户端都正确的显示的信息。截图如下:
我们启动了三个客户端,都得到了返回到消息。
我们上面的例子是使用的Tcp通道的方式进行传输消息对象的,那么他和Http通道有什么区别以及在什么情况下应该用什么通道呢?
1.Tcp是通过将对象格式化为二进制流来进行传输的,而Hppt则是通过格式化为符合soap协议的消息流。前者的传输效率较高,而后者因为符合soap协议所有更加具有交互性。
2.如何您的应用需要穿越防火墙或者您的服务端是在IIS上面,那么您应该使用Http通道来进行传输,因为防火墙是不拦截Http消息的。而如果您对前面的要求不高,那么推荐您使用Tcp传输,因为它对传输大的对象消息有优势,更有效率。