.Net远程方法调用研究

简介
远程方法调用发展到现在,已经有以下几种框架实现:DCE/RPC,CORBA,DCOM,MTS/COM+,Java RMI,Java EJB,Web Services/SOAP/XML-RPC,NET Remoting,本文主要介绍了.NET远程方法调用的原理,实现以及与微软COM/DCOM实现的异同点。

框架
Microsoft .NET Remoting 提供了一种允许对象通过应用程序域与另一对象进行交互的框架。众所周知,Web服务仅仅提供了一种简单的容易理解的方法来实现跨平台,跨语言的交互,而DotNet Remoting相对于Web服务就像Asp相对于CGI那样,实现了一种质的转变。DotNet Remoting提供了一个可扩展的框架,它可以选择不同的传输机制(HTTP和TCP是内置的),不同的编码方式(SOAP以及二进制代码),安全设置(IIS或SSL),同时提供了多种服务,包括激活和生存期支持。

远程方法调用
对于远程方法调用来说,最直接的问题恐怕是:一个本地方法,推而广之,一个本地对象,如果放在网络环境中,如何传递这个方法的调用,返回,如何传递这个对象的请求。虽然对于应用开发人员来说这个并不是必不可少的事,但对于我们学习分布式操作系统来说,我想这是应该搞清楚的。我们知道,DCOM协议也被称为对象RPC,它建立在DCE RPC协议基础上,也就是说,在网络传输这一层,它必须使用特殊的协议。另外Windows RPC 机制要求熟悉的类型和使用 IDL 工具的封送处理知识,并向开发人员公开 RPC 客户端和服务器存根的管理。Remoting 在为 .NET 提供 RPC 时要容易得多,而且由于使用简单易懂的 .NET 数据类型,从而消除了早期 RPC 机制中存在的类型不匹配的情况(这是一个非常大的威胁)。配置为使用 HTTP 或 TCP 协议,并使用 XML 编码的 SOAP 或本机二进制消息格式进行通信。开发人员可以构建自定义的协议(通道)或消息格式(格式化程序),并在需要时由 Remoting 框架使用。服务器和客户端组件都可以选择端口,就象可以选择通信协议一样。由此带来的一个好处是,很容易建立并运行基本的通信。

下图中描述了.Net Remoting的五要素:

代理:在Client端伪装为Remote Objects并转发对Remote Objects的调用。

Message:消息对象包含了执行Remote Methods调用的必要数据参数。

Message Sink/Channel Sink:在Remote调用中,Message Sink允许定制消息处理流程,这是.Net Remoting内置的可扩展特性。

Formatter:也是Message Sink,用来序列化消息,已适于网络传输,如SOAP。

Transport Channel:也是Message Sink,用来传输序列化的消息到远程进程,如HTTP。

当访问Remote Objects时,Client端application并不处理真实对象的引用,而是仅仅调用Proxy对象的方法。Proxy对象提供与Remote Objects相同的接口,伪装成Remote Objects。Proxy对象自己并不执行任何方法,而是以消息对象(Message Object)的形式转发每一个方法调用给.Net Remoting Framework。

在类型支持方面,DCOM提供了一套复杂的列集和散集机制,他建立在RPC的基础上。由于RPC被定义为DCE标准的一部分,而DCE RPC定义了所有常用的数据类型的数据表达方法,即网络数据表示法。为了使存根(stub)代码和代理对象能够正确地对参数和返回结果也进行列集和散集,它们应该使用一致的数据表示法NDR,以便在不同的操作系统环境下也能够远程调用。

This figure is from the book named Advanced .Net Remoting.

反过来,我们再看看.NET Remoting 强大的类型操作,.Net Remoting 支持所有托管的类型、类、接口、枚举、对象等,这通常被称为“多类型保真”。这里的关键在于,如果客户端和服务器组件都是在应用程序域中运行的 CLR 托管的对象,则数据类型的互操作是不成问题的。从根本上讲,我们拥有的是一个封闭的系统,会话的两端可以完全被理解,因此我们可以充分利用这一事实,处理好用于通信的数据类型和对象。

在各种系统并存的情况下,我们需要考虑系统之间的互操作性。对于可互操作的数据类型,我们要谨慎处理。例如,Web 服务数据类型的定义要基于 XML 架构定义 (XSD) 关于数据类型的说明。任何可以使用 XSD 进行描述并可以在 SOAP 上进行互操作的类型都可以使用。但是,这也确实使得某些数据类型不能使用。

代理
代理对象伪装成一个远程对象,并且向本地提供远程对象相同的接口。客户端应用程序与处理远程“真实”对象的应用(包括内存引用,指针,等等),都是通过代理对象实现的。代理对象当然并不自己完成方法调用,它将请求作为消息对象传给.NET Framework。在这一方面,.Net Remoting 和DCOM思想上是一致的。当某个客户端激活一个远程对象时,框架将创建 TransparentProxy 类的一个本地实例(该类中包含所有类的列表与远程对象的接口方法)。因为 TransparentProxy 类在创建时用 CLR 注册,所以代理上的所有方法调用都被运行时截取。这时系统将检查调用,以确定其是否为远程对象的有效调用,以及远程对象的实例是否与代理位于同一应用程序域中。如果对象在同一个应用程序域中,则简单方法调用将被路由到实际对象;如果对象位于不同的应用程序域中,将通过调用堆栈中的调用参数的 Invoke 方法将其打包到 IMessage 对象并转发到 RealProxy 类中。此类(或其内部实现)负责向远程对象转发消息。TransparentProxy 类和 RealProxy 类都是在远程对象被激活后在后台创建的,但只有 TransparentProxy 返回到客户端。在代理对象创建时,需要引用Client端的Messag Sink Chain,Sink Chain的第一个Sink对象的引用保存在RealProxy对象的Identity属性。如下图所示:

所以,在下面这段代码调用new或者GetObject获得对象后,对象obj将会指向

TransparentProxy对象。

HttpChannel channel = new HttpChannel();

ChannelServices.RegisterChannel(channel);

SomeClass obj = (SomeClass) Activator.GetObject(

type of(SomeClass),

"http://localhost:1234/SomeSAO.soap");

消息
当一次函数调用指向远程对象的引用时,TransparentProxy创建一个MessageData对象并且将它传给RealProxy对象的PrivateInvoke()调用,RealProxy相应地生成一个新的Message对象并且以MessageData对象为参数调用其InitFields()方法,Message将会解析MessageData对象中地指针进行相应地函数调用。当处理结束时,将会返回一个包含回应消息的IMessage对象,RealProxy将会调用它自己的HandleReturnMessage()方法,该方法检查参数并且调用PropagateOutParameters()方法。当处理结束后RealProxy将会从它的PrivateInvoke()方法中返回,IMessage将会返回给TransparentProxy。CLR保证函数返回值与其返回格式相符,所以对于应用程序来说,它仅仅认为这是一个一般方法的调用,返回,这正是分布式的最终要求。

可以看到,.NET Remoting与DCOM的底层机制已经完全不同了,DCOM的一次方法调用,需要经过列集(marshaling)和散集(unmarshaling)的处理,包括创建代理对象和转载存根代码等。但是可以看到.NET做为DCOM的下一代,在基本思想上和DCOM是一脉相承的。在我学习到现在的体会看来,.NET面向Web服务的RPC机制的确是一大革新,让我们看看IMessage怎么进行传递的:

这是一个消息穿过Transport Channel(也就是Message Sink)的实例。

首先是SOAP远程调用的HTTP请求:

POST /MyRemoteObject.soap HTTP/1.1

User-Agent: Mozilla/4.0+(compatible; MSIE 6.0; Windows 5.0.2195.0; MS .NET

Remoting;

MS .NET CLR 1.0.2914.16 )

SOAPAction:

"http://schemas.microsoft.com/clr/nsassem/General.BaseRemoteObject/General#

setValue"

Content-Type: text/xml; charset="utf-8"

Content-Length: 510

Expect: 100-continue

Connection: Keep-Alive

Host: localhost

然后是一个对于一个远程对象setValue(int):

POST /MyRemoteObject.soap HTTP/1.1

User-Agent: Mozilla/4.0+(compatible; MSIE 6.0; Windows 5.0.2195.0; MS .NET

Remoting;

MS .NET CLR 1.0.2914.16 )

SOAPAction:

"http://schemas.microsoft.com/clr/nsassem/General.BaseRemoteObject/General#

setValue"

Content-Type: text/xml; charset="utf-8"

Content-Length: 510

Expect: 100-continue

Connection: Keep-Alive

Host: localhost

<SOAP-ENV:Envelope

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:xsd="http://www.w3.org/2001/XMLSchema"

xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"

xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"

SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"

xmlns:i2=

"http://schemas.microsoft.com/clr/nsassem/General.BaseRemoteObject/General">

<SOAP-ENV:Body>

<i2:setValue id="ref-1">

<newval>42</newval>

</i2:setValue>

</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

看起来是多么美妙的形式啊,完全摆脱了分析RPC时的痛苦,不过我始终还是有疑问,微软如果始终坚持windows操作系统一统的路线,.NET的真正跨平台性是否真正能实现。

一种常见的 Microsoft 理论是:如果需要在不同系统之间进行互操作,应该选择使用开放标准 (SOAP、XML、HTTP) 的 Web 服务方法,而使用 .NET Remoting 决不是一种交互的解决方案;如果各种系统中的所有组件都是 CLR 托管的,则 .NET Remoting“可能”是正确的选择。

我想我还漏了一个重要的问题:串行化(Serialization)。这是实现跨进程调用的关键技术。在COM中串行化使通过列集(marshaling)和散集(unmarshaling)完成的,列集过程的复杂程度因参数类型而异,简单的入WORD或float只需按二进制序列填到数据包中,复杂的参数如指针需要考虑整个指针层次,获得所有的数据全部。散集是和列集向对应的过程,远程机器的存根代码接受到列集数据后,重新建立堆栈的过程就是散集,每次远程调用至少经过两次列集和两次散集,因为返回值也需要列集回来再散集。COM的一个问题就是在于其过于复杂的的参数传递问题这一套复杂的机制是很难搞明白,更何况对于代码的定制了。.NET Remoting对于串行化的处理是通过一个formatter来完成的,.NET Remoting框架给你提供了两个缺省的formatters,SoapFormatter和BinaryFormatter,它们都能通过HTTP或TCP进行传输。在消息完成了ImessageSink对象的预处理链后,它将通过SyncProcessMessage()到达formatter。在客户端,SoapClientFormatterSink将IMessage传给SerializeMessage()方法。这个函数设置TransportHeaders,请求它的NextSink(HttpClientTransportSink ),它将创建一个ChunkedMemoryStream并且传给channel sink.。真正的串行化由CoreChannel.SerializeSoapMessage()开始,它建立一个SoapFormatter,并且调用其Serialize()方法,下面是一个对于obj.setValue(42)方法的SOAP输出

<SOAP-ENV:Envelope

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:xsd="http://www.w3.org/2001/XMLSchema"

xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"

xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"

SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"

xmlns:i2="http://schemas.microsoft.com/clr/nsassem/General.BaseRemoteObj ***

ect/General">

<SOAP-ENV:Body>

<i2:setValue id="ref-1">

<newval>42</newval>

</i2:setValue>

</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

这种方式与COM比较更加清晰,易懂,并且也确实易于开发,例如我们可以实现一个压缩的Sink。下面是开发一个CompressionSink的骨架例程,从这来看,COM实在是望尘莫及。

using System;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Messaging;

using System.IO;

namespace CompressionSink

{

public class CompressionClientSink: BaseChannelSinkWithProperties,

IClientChannelSink

{

private IClientChannelSink _nextSink;

public CompressionClientSink(IClientChannelSink next)

{

_nextSink = next;

}

public IClientChannelSink NextChannelSink

{

get {

return _nextSink;

}

}

public void AsyncProcessRequest(IClientChannelSinkStack sinkStack,

IMessage msg,

ITransportHeaders headers,

Stream stream)

{

// TODO: Implement the pre-processing

sinkStack.Push(this,null);

_nextSink.AsyncProcessRequest(sinkStack,msg,headers,stream);

}

public void AsyncProcessResponse(IClientResponseChannelSinkStack sinkStack,

object state,

ITransportHeaders headers,

Stream stream)

{

// TODO: Implement the post-processing

sinkStack.AsyncProcessResponse(headers,stream);

}

public Stream GetRequestStream(IMessage msg,

ITransportHeaders headers)

{

return _nextSink.GetRequestStream(msg, headers);

}

public void ProcessMessage(IMessage msg,

ITransportHeaders requestHeaders,

Stream requestStream,

out ITransportHeaders responseHeaders,

out Stream responseStream)

{

// TODO: Implement the pre-processing

_nextSink.ProcessMessage(msg,

requestHeaders,

requestStream,

out responseHeaders,

out responseStream);

// TODO: Implement the post-processing

}

}

}

小结
以上就是我几天来对.NET Remoting的学习所得。我的学习主要集中在.NET Remoting的远程方法传递这方面,因为我觉得这才是RPC最关键的技术。从几天的学习所得,可以看出.NET FrameWork的确是一种技术,思想都非常先进的框架。我唯一的怀疑在于微软所谓的平台无关性,这方面,JAVA也许永远胜出一筹。

这篇文章0.1版放在我的blog上 http://blog.csdn.net/drizt/

时间: 2024-12-12 20:36:24

.Net远程方法调用研究的相关文章

从8个方面对移动设备阅读体验进行研究学习

一直想对移动设备阅读体验进行较为完整的研究和学习,但内容太多,涉及到非常多的传统平面设计知识,目前仅初步地完整字体部分.完整的研究框架包括: 1.界面版式设计的方法.常用的栅格分割适合移动设备多分辨率复杂内容的自动排版,内容可控制时是否可以模仿杂志的复杂不规则排版方式,以达到最佳的阅读体验. 2.移动设备上最佳的字体有什么必要的设计要素?如下图,更多的内容包括字体颜色.字间距.行间距和字体渲染等,不同的内容需要不同的字体.随着屏幕分辨率和显示精度的发展,字体也有一个进化过程. 3.屏幕亮度等参数

头文件 函数主体-急!!研究源代码,找不到函数的主体!

问题描述 急!!研究源代码,找不到函数的主体! 为什么用sourcelight察看源代码会发现有些函数只在头文件中定义了,但却找不到函数的主体? /* database handling */ extern int cl_load(const char *path, struct cl_engine **engine, unsigned int *signo, unsigned int options); extern const char *cl_retdbdir(void); 就是这两个函数

CCAI 2017 日本理化学研究所先进智能研究中心主任杉山将:弱监督机器学习的研究进展

在本次大会上,日本人工智能和机器学习领域新一代的代表性人物--日本理化学研究所先进智能研究中心主任Masashi Sugiyama(中文名:杉山将)为参会者带来了<弱监督机器学习的研究进展>的演讲.杉山将在机器学习领域发表过很多重要的理论,是这个领域最知名的学者之一,出版了机器学习相关书籍<图说机器学习>(中文版). 以下内容根据杉山将本次主题演讲整理,略有删减: 大家早上好,我叫杉山将,非常高兴能够参加今天的大会,也很高兴和这么多中国的研究人员见面,我也特别喜欢杭州的文化和当地的

用户研究:不同群体在各时段完成调研问卷的情况对比

文章描述:调研问卷投放时间的探讨. 写在前面:本研究暂不涉及周几投放更合理,主要有两点考虑:1.日常调研项目基本都有执行周期的限定,一般都是越能尽快投放越好,且基本都在工作日投放:2.目前执行的调研项目,周几投放的都有,如果时间允许,都会持续一周收集数据,整体的打开率波动不大. 引子 在日常研究工作中,为了提高问卷调研的科学性.增加填答问卷用户的随机性,针对买家的问卷调研,我们一般会采用Email发送调研邀请的方式:针对卖家,会采用站内信和Email的方式.同时为减少对用户的骚扰,他们可以选择退

shogun python-现在还有没有研究过shogun啊?

问题描述 现在还有没有研究过shogun啊? shogun安装了一星期了还没装上QAQ $ mkdir build && cd build $ cmake -DCMAKE_INSTALL_PREFIX="$HOME/shogun-install" -DPythonStatic=ON .. $ make $ sudo make install 安装完没有sg.so,没法运行静态python接口啊 解决方案 http://www.shogun-toolbox.org/doc

.Net开发平台研究(一

.Net开发平台研究 总结: .Net开发平台的发布标志着近十年来微软开发平台第一个重大的转变.这个开发平台包括一个用于加载和运行应用程序的新的软件基础结构(.NET Framework和ASP.NET),一个新的开发环境(Visual Studio .NET),以及支持该结构的编程语言. 微软希望随着这个新平台的发布,评论不再将这个平台作为朦胧的软件,而且开发者也将发现该平台使得Windows上Web应用程序(尤其是Web Service)的开发更为容易.这样或许会使更多的开发者拥护公司的操作

UX从门外汉开始的用户研究之路

  笔者非科班出身,始终习惯以局外人眼光审视这个工种和我自身.过去几年中,接触过各种国内外公司.研究院中的用户体验团队.正是见惯了各种UXC/UED/UXD局限,所以带着从头再来的想法和满身的匪气来到现在公司. 2年过去,虽仍旧一事无成,但于丛林化的做事方式,吃的苦头和心得都良多.今天和大家分享一二.不论逻辑,点到即止. 刻意模糊的定位:谁在乎你叫什么. 无论是否甘心承认,UX更像过程工种.如果不服,想想自己过去一年最大的成绩,然后是否有勇气告诉公司老板去要求加薪. 成王败寇的领域,没人在意你具

ftp服务器-毕设求大神指点!!题目是基于SaaS模式的分布式FTP服务器技术研究

问题描述 毕设求大神指点!!题目是基于SaaS模式的分布式FTP服务器技术研究 内容是: 目前,云计算正在各领域得到越来越多的应用,出现了多种云计算环境,掌握云计算的概念,熟悉相关云计算平台上的软件开发方法,对提高学生综合运用所学知识解决实际问题具有十分重要的现实意义.作为云计算平台之一的百度云,已得到了广泛应用, 本课题在理解FTP服务器模式的前提下,在saas环境下建立分布式的ftp服务,用户可通过ftp客户端传送数据. 该课题具有以下要求: 1. 了解云计算的基本原理,掌握基于saas的开

int类型-求解,研究了一晚都没研究好!

问题描述 求解,研究了一晚都没研究好! sun是int类型,count是int类型,sum能正常输出一个数字,sun/count就报错. 解决方案 sun/count 出错,出什么错呢?一般来说,sun/count 时,如果两个变量都是 int 类型,/ 的结果也是 int 类型.如果 sun/count 的结果是一个浮点类型,对于 C 语言来说不会是浮点类型.不知道你的编程环境是什么?