.Net远程方法调用研究__教程 |
|
日期:2007-5-20 1:21:10 人气:103 [大 中 小] |
|
|
|
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输出 |
|
出处:本站原创 作者:佚名 |
|
|