享受代码,享受人生

SOA is an integration solution. SOA is message oriented first.
The Key character of SOA is loosely coupled. SOA is enriched
by creating composite apps.
posts - 207, comments - 2333, trackbacks - 152, articles - 44
  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理

Remoting基本原理及其扩展机制(上)

Posted on 2007-01-04 13:16 idior 阅读(12955) 评论(40)  编辑 收藏 网摘 所属分类: .Net Distributed App

.NET Remoting是.NET平台上允许存在于不同应用程序域中的对象相互知晓对方并进行通讯的基础设施。调用对象被称为客户端,而被调用对象则被称为服务器或者服务器对象。简而言之,它就是.NET平台上实现分布式对象系统的框架。

传统的方法调用是通过栈实现,调用方法前将this指针以及方法参数压入线程栈中,线程执行方法时将栈中的参数取出作为本地变量,经过一番计算后,将方法的返回结果压入栈中。这样我们就完成了一次方法调用。如下图所示:



基于栈的方法调用在同一个应用程序域中很容易实现,但是如果要调用的方法所属的对象位于另一个应用程序域或另一个进程甚至是另一个机器,又当如何?应用程序域之间是无法共享同一个线程栈的,此时我们将转而使用另一种方法调用机制——基于消息的方法调用机制。在客户端通过代理对象将原先基于栈的方法调用信息(定位远程对象的信息、方法名、方法参数等)封装到一个消息对象中,再根据需要将这些消息对象转化成某个格式的数据流发送到远程对象所在的的应用程序域中。当经过格式化的消息到达服务器后,首先从中还原出消息对象,之后在远程对象所在的的应用程序域中构建出相应方法调用栈,此时就可以按照传统的基于栈的方法调用机制完成方法的调用,而方法返回结果的过程则按照之前的方法反向重复一遍。如下图所示:

在基于消息的远程方法调用中主要有以下几个重要角色:

Client Proxy: 负责在客户端处理基于栈的参数传递模式和基于消息的参数传递模式之间的转换。

Invoker:与Client Proxy的功能相反。

Requestor: 负责将消息对象转换成可在网络上传输的数据流,并将其发送到服务器。

Marshaller: 负责消息对象的序列化与反序列化。

Client Request Handle:负责以数据流的格式发送客户端的请求消息。

Server Request Handel:负责接收来自客户端的请求消息。

那么在.NET Remoting框架下,这些重要角色又各自对应了哪些对象呢?下图是一个Remoting框架的示意图:


图1

从中我们可以看到客户端的Transparent Proxy与服务器端的StackBuilderSink分别扮演了Client Proxy与Invoker的角色。Remoting依靠这两个对象实现了基于栈的方法调用与基于消息的方法调用的转换,并且这一过程对于开发者是完全隐藏的。

Marshaller的角色由Formmatter Sink完成,在Remoting中默认提供了两种Fommatter:一个实现了消息对象与二进制流的相互转换,另一个实现了消息对象与Soap数据包的相互转换,而支持Soap格式则说明Remoting具有实现Web Service技术的可能。

Client Request Handle与Server Request Handel都是.NET中实现网络底层通讯的对象,如HttpWebRequest、HttpServerSocketHandler等。在Remoting中我们并不直接接触这些对象,而是通过Channel对它们进行管理。在框架中默认提供了三种Channel:HttpChannel、TcpChannel与IpcChannel。但是在上面这副图中,我们并没有看到Channel对象,那么Channel又是如何影响网络底层的通讯协议的呢?

其实在上面这幅图中,真正能对通讯时所采用的网络协议产生影响的元素是Transport Sink,对应不同的协议Remoting框架中提供了三种共计六个Transport Sink:HttpClientTransportSink、HttpServerTransportSink与TcpClientTransportSink、TcpServerTransportSink以及IpcClientTransportSink、IpcServerTransportSink,它们分别放置在客户端与服务器端。既然Transport Sink才是通讯协议的决定元素,那么Channel肯定与它有着某种联系,让我们先暂时搁置此话题,留待后面进一步介绍。

观察上面这副图,我们可以发现其中包含了一系列的Sink,而所谓的Sink就是一个信息接收器,它接受一系列的输入信息,为了达到某种目的对这些信息做一些处理,然后将处理后信息再次输出到另一个Sink中,这样一个个的Sink串联起来就构成了一个Pipeline(管道)。Pipeline模式在分布式框架中经常可以看到,应用该模式可以使框架具有良好的灵活性。当我们需要构建一个系统用于处理并转换一串输入数据时,如果通过一个大的组件按部就班的来实现此功能,那么一旦需求发生变化,比如其中的两个处理步骤需要调换次序,或者需要加入或减去某些处理,系统将很难适应,甚至需要重写。而Pipeline模式则将一个个的处理模块相互分离,各自独立,然后按照需要将它们串联起来即可,此时前者的输出就会作为后者的输入。此时,每个处理模块都可以获得最大限度的复用。当需求发生变化时,我们只需重新组织各个处理模块的链接顺序,或者删除或加入新的处理模块即可。在这些处理模块(Sink)中最重要的两类是Formatter Sink与Transport Sink,也就是图1中的红色部分,当我们需要通过网络访问远程对象时,首先要将消息转化为可在网络上传播的数据流,然后需要通过特定的网络协议完成数据流的发送与接收,这正是这两类Sink所负责的功能。虽然它们本身也可以被自定义的Sink所替换,不过Remoting中提供的现有实现已经可以满足绝大多数的应用。

那么.NET Remoting中又是如何创建这个Pipeline的呢?以HttpChannel为例,在创建客户端的Pipeline的时候,会调用它的CreateMessageSink方法,此时又会进一步调用HttpClientChannel的构造函数,在构造函数中调用了一个名为SetupChannel()的私有方法,看一下它的实现:

private void SetupChannel()
{
if (this._sinkProvider != null)
{
CoreChannel.AppendProviderToClientProviderChain(this._sinkProvider,
new HttpClientTransportSinkProvider(this._timeout));
}
else
{
this._sinkProvider = this.CreateDefaultClientProviderChain();
}
}

再看看在没有提供自定义SinkProvider的默认情况下CreateDefaultClientProviderChain()会创建出哪些Sink


private IClientChannelSinkProvider CreateDefaultClientProviderChain()
{
IClientChannelSinkProvider provider = new SoapClientFormatterSinkProvider();
provider.Next = new HttpClientTransportSinkProvider(this._timeout);
return provider;
}

其中包含了SoapClientFormatterSinkProvider与HttpClientTransportSinkProvider,自然地,到了创建Pipeline的时候,它们会分别创建出SoapClientFormatterSink与HttpClientTransportSink,前者用于实现消息对象的Soap格式化,而后者则表示将用Http协议来实现消息的通讯。这样我们就明白了为什么使用HttpChannel就会采用Http协议作为网络通讯协议,并且消息将以SOAP格式传递。但是仔细观察SetupChannel方法中的下段代码,我们可以发现通过提供自定义的SinkProvider,我们可以改变消息的编码格式,因为此时只创建了一个HttpClientTransportSinkProvider,并没有定义FormatterSinkProvider,而FormatterSinkProvider完全可以在自定义的SinkProvider中自由设定。

   if (this._sinkProvider != null)
{
CoreChannel.AppendProviderToClientProviderChain(this._sinkProvider,
new HttpClientTransportSinkProvider(this._timeout));
}

那么我们又如何在.NET Remoting中定义自己的SinkProvider并让它发挥作用呢?下面这幅图演示如果使用自定义SinkProvider对Pipeline进行定制。

 

图2

首先在配置文件中引用自定义的ChannelSinkProvider的类名及其所在程序集,然后编写自定义的ChannelSinkProvider的具体实现,也就是加入你需要的ChannelSink,最后在自定义的ChannelSink中实现具体的处理操作。这样我们向Pipeline中成功地添加了自定义处理模块。这里需要提醒大家注意,接收方的Pipeline信道与发送方Pipeline之间存在着一个根本的差异。发送方Pipeline为每个远程对象的真实代理创建一个接收器(Sink)链。接收方信道在其创建之时创建了接收器(Sink)链,这条链将为所有通过这个接收方Pipeline进行转送的调用所使用,不论与这个调用相关联的对象是哪个。下图展示了这个差异:


图3

细心的读者可能已经注意到之前我们定制的是ChannelSink,为什么要加上一个Channel呢?让我们回过头去再看看图1,其中有两个绿色的Sink,他们都是Remoting中可选的组件,也是我们对Pipeline进行扩展的地方。你可以在这两个地方加入自定义的Sink,从而对流经Pipeline的数据做某些需要的处理,前者需实现IMessageSink接口,后者需要实现IXXXChannelSink接口,那么它们又有何不同呢?注意看图1,我们会发现其中隔了一个Formmatter Sink,而Formmatter Sink的作用就是将原来的.NET消息变成可在网络上传播的数据流(可以是Binary或Soap格式),这也就表明前者的输入是消息对象,而后者的输入是数据流(Stream)。这也就决定了他们各自所能实现的扩展功能是不同的。比如,操作消息对象,我们可以把远程方法的参数变一变(比如从英文翻成中文),而操作数据流,我们可以实现数据流的加密或压缩之类功能。如何定制新的ChannelSink并将其加入到Pipeline中已经在图2中演示过了,那么MessageSink呢?请关注下节内容。

系列文章 

参考资料:

《Advanced Remoting》

《Pattern oriented software architecture vol1》

《Remoting Patterns》

《Pratical .NET2 and C#2》

---

做个小广告,最近刚刚与博客园中的一些朋友合作翻译完了《Pratical .NET2 and C#2》一书,这本针对初级到中级开发人员的洋洋900页的书,对.NET 2.0的讨论不光详尽,而且深入浅出,中间还穿插了很多C#例码。可以说这是市面上介绍.NET 2.0最全面且非常有深度的一本书,其中涉及各个方面的话题,如CLR、类型系统、安全性、XML、Winform、ASP.NET、Remoting、进程线程与同步、事务、Webservices等等,每个话题的介绍都非常深入并且与.NET2.0紧密关联,不像以往的书仅仅是点到为止,在翻译这本书的过程中我也学到很多新的知识,而且在翻译过程中我和脑袋都在找工作,我们把它戏称为《.NET面试宝典》。尽管由于涉及话题较多,有些章节叙述的不是那么连贯,但是这本书不乏一些精彩章节,比如介绍CLR、进程线程与同步、Remoting以及反射的这些章节就非常精彩,很多内容在其他书中都不曾有过介绍。等翻译完全定稿后,我们会在博客园公布一些样章,到时欢迎大家浏览。总之,这是一本相当不错的书,并且在Amazon上评价也很高。

Feedback

#1楼    回复  引用  查看    

2007-01-04 14:14 by fds2003[匿名]      
终于见到你的大作了!!:)

#2楼    回复  引用  查看    

2007-01-04 14:16 by fds2003[匿名]      
找个时间买《Pratical .NET2 and C#2》看看

#3楼    回复  引用    

2007-01-04 14:16 by swnuwangyun[匿名] [未注册用户]
及时雨啊,正需要这样的文章呢,谢谢

#4楼 [楼主]   回复  引用  查看    

2007-01-04 14:26 by idior      
@fds2003[匿名]
尚未出版,现在刚刚翻译完,估计上半年能够出版。印象中也没有影印版。
@swnuwangyun[匿名]
那就巧了 :)

#5楼    回复  引用  查看    

2007-01-04 14:34 by swnuwangyun      
呵呵,我以前有一个想法:为.Net Remoting增加基于SKYPE API的P2P传输通道 ,在随笔http://www.cnblogs.com/swnuwangyun/archive/2006/11/10/556880.html 中有描述,可惜一直没有精力去实现,回头再仔细研究下你的文章:)

#6楼    回复  引用    

2007-01-04 15:02 by robinz-hbifts [未注册用户]
用WCF吧~ :)
Remoting没前途了...

#7楼    回复  引用    

2007-01-04 15:08 by 小春[匿名] [未注册用户]
提个问题:以前曾听过一朋友,他说remoting有公里限制。如果客户端和服务端超过多长的距离,性能会有很大的降低。

迷茫。跟网络的关系吗?

#8楼    回复  引用  查看    

2007-01-04 15:12 by iceboundrock      
@小春[匿名]
呵呵,除非remoting的C/S间是用模拟信号传递数据的,否则不会有这个问题

#9楼 [楼主]   回复  引用  查看    

2007-01-04 15:15 by idior      
@robinz-hbifts
WCF也是用的Pipeline嘛,原理都是类似的。

#10楼    回复  引用  查看    

2007-01-04 15:28 by JesseZhao      
我最近也在看WCF,感觉是项很有前途的技术,我很喜欢这个技术。你的文章写的很专业,I like it!!!

#11楼    回复  引用    

2007-01-04 16:07 by 无天刀绝 [未注册用户]
WCF只不过是现有一些技术的整合,想了解WCF内部运行机制,还是需要看楼主这样的文章。

#12楼    回复  引用    

2007-01-04 17:03 by Dah[匿名] [未注册用户]
原创要支持!~ 收藏了~

#13楼    回复  引用  查看    

2007-01-04 19:40 by Anders Cui      
同意楼上的,要多一些这种好的原创文章

#14楼 [楼主]   回复  引用  查看    

2007-01-04 19:56 by idior      
@Dah[匿名]
@JesseZhao
@Anders Cui
@无天刀绝
感谢大家的支持,好的原创文章需要大家的努力,博客园一直都在鼓励大家写出更好的原创文章。

@无天刀绝
WCF技术的目的是为了将现有的多项分布式技术统一到一个编程模型下,所以它的整个框架还是具有独创性的,我以后也会争取对它做一些介绍。另外在写完这个下篇后,我将介绍WSE的原理及其扩展机制。

#15楼    回复  引用  查看    

2007-01-04 21:17 by SW515[匿名]      
图文并茂,原创好文!up

#16楼    回复  引用  查看    

2007-01-05 08:49 by Robert Lee      
好久没有看到楼主的文章了,不过一出手就是精品,受教了:D

#17楼    回复  引用  查看    

2007-01-09 15:50 by Hunts.C      
Mark:)

#18楼    回复  引用    

2007-01-09 23:29 by anonymous [未注册用户]
小弟愚昧请教
remoting中是否能够穿透firewall,这个firewall指的是? 我现在如果将写好的remoting服务部署在internet的一台服务器上. 然后internet上的其他的client去访问是否就会存在firewall的问题? 没有的可以访问,有的就没法访问?

#19楼    回复  引用    

2007-01-09 23:30 by anonymous [未注册用户]
如果部署成Httpchannel的方式可以穿透firewall,那么性能和效率上相比webservice如何? 小弟因为现在ws调用效率太地,欲转向remoting,所以请教.

#20楼 [楼主]   回复  引用  查看    

2007-01-10 10:45 by idior      
@anonymous
使用http协议的80端口一般可以穿越防火墙,如果使用http信道加上soap formatter,基本上与ws没什么区别,不过在对象的序列化方式有点不一样。
如果是性能问题,你可以使用http信道加上binary formatter,这样既可以穿越防火墙,性能也会得到提升。不过此时客户端必须也使用.net平台。

#21楼    回复  引用    

2007-03-04 20:13 by none [未注册用户]
文章写得很不错,我现在就是不知道如何写文章?请赐教

#22楼    回复  引用  查看    

2007-03-06 15:19 by Artech      
好文章,受教了!我对分布式技术很感兴趣,有机会一起探讨。

#23楼    回复  引用  查看    

2007-03-06 16:40 by yangli      
顺便问一下,不知道您有没有关于Socket在.NET下的研究,因为个人感觉有时.NET Remoting的应用范围不如Socket来得广,但是这方面也一直没有找到比较完整的资料,多谢了~

#24楼 [楼主]   回复  引用  查看    

2007-03-06 18:59 by idior      
@none
在平时的工作或学习中发掘自己感兴趣的话题,并加以深入研究,总是能写出点东西的,文章的关键在于有自己的想法。
@Artech
看了你之前发表的一些文章,我也有问题想和你探讨一下。
@yangli
Socket我没有深入研究过。期待您的大作。 :)
Socket更加基础更加原始一点,在目前的分布式应用中很少直接使用它了。

#25楼    回复  引用    

2007-03-06 23:34 by man [未注册用户]
文章写过很好,
请问可以可以提供一个demo下载吗?或者发一份给我好吗?(wanyong775@163.com)
谢谢

#26楼    回复  引用  查看    

2007-03-07 13:24 by 文炽城      
好文章```支持``

#27楼    回复  引用    

2007-05-10 19:15 by zhanmin_mail [未注册用户]
看了你的文章,安图2的样子写了个channelsink,但是调用不了,我已经在配置文件中加了
<clientProviders>
<formatter ref ="binary"/>
<provider type ="TimeClient.myClientSinkProvider, TimeClient"/>
</clientProviders>
郁闷,可否给个实现了的Demo?谢谢 zhanmin_mail@163.com

#28楼 [楼主]   回复  引用  查看    

2007-05-10 22:22 by idior      
@zhanmin_mail
@man
抱歉,暂时没有demo,以后的文章中一定提供demo下载。

#29楼    回复  引用  查看    

2007-05-31 15:57 by Xt Idt      
我想问的也是firewall的问题啊!!

#30楼    回复  引用    

2007-06-14 09:20 by hj [未注册用户]
问一下这本《Pratical .NET2 and C#2》网上哪有卖呢

#31楼    回复  引用    

2007-06-14 17:58 by idior [未注册用户]
@hj
再过一个月左右应该上市了

#32楼    回复  引用  查看    

2007-07-19 15:33 by 万朗      
好文!

#33楼    回复  引用  查看    

2007-12-09 12:02 by 蛙蛙池塘      
你的书该出版了吧

#34楼    回复  引用  查看    

2007-12-27 23:06 by 蛙蛙池塘      
你好,我写了一个MyTcpClientTransportSink和MyTcpClientTransportSinkProvider(看了你的文章,并反射了system.runntime.remoting.dll后写成的。),我想让我的remoting客户端使用我自己的MyTcpClientTransportSink与服务端通信,下面是我的完整的客户端配置文件,可是不起作用,请帮忙写一个全的配置文件,谢谢。
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.runtime.remoting>
      <channels>
        <channel
           type="System.Runtime.Remoting.Channels.Tcp.TcpChannel, System.Runtime.Remoting"
           id="tcpbinary"
         >
          <clientProviders>
            <provider type="WawaSoft.Remoting.Channels.Tcp.TcpClientTransportSinkProvider,ImpsRemoting" />
            <formatter  type="System.Runtime.Remoting.Channels.BinaryClientFormatterSinkProvider, System.Runtime.Remoting"
               />
          </clientProviders>
        </channel>
      </channels>
  </system.runtime.remoting>
</configuration>

程序里调用如下
try
{
Hashtable props = new Hashtable();
props["name"] = "tcp_rem";
props["timeout"] = 1000;
TcpChannel _tcpChannel = new TcpChannel(props, null, null);
ChannelServices.RegisterChannel(_tcpChannel, false);

ServerObject so = (ServerObject)Activator.GetObject(typeof(ServerObject), "tcp://127.0.0.1:8080/ServerObject");
Console.WriteLine(so.SayHello("onlytiancai"));
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
Console.Read();

#35楼 [楼主]   回复  引用  查看    

2007-12-28 00:26 by idior      
@蛙蛙池塘
我现在已经很久没做remoting的开发了,而且我也不清楚你的具体情况,实在没有时间帮你做这些具体的配置。

#36楼    回复  引用  查看    

2007-12-28 10:38 by 蛙蛙池塘      
好,谢谢,我自己看看。

#37楼    回复  引用  查看    

2008-04-27 17:31 by 活到老,学到老      
学习了

#38楼    回复  引用    

2008-09-29 13:55 by King2008 [未注册用户]
是否可以扩展UDP协议呢?

#39楼    回复  引用  查看    

2008-12-01 21:33 by 坏人      
mark

标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2007-03-07 11:32 编辑过
Google站内搜索
[推荐职位]上海盛大网络招聘架构师



China-pub 计算机图书网上专卖店!6.5万品种 2-8折!
近千种 9-95 新二手计算图书火热销售中!
开发者征途系统新作:《设计模式——基于C#的工程化实现及扩展》

相关文章:

相关链接: