深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上鸿蒙开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
一旦应用程序(客户端)引用了远程对象,就可以进行远程调用了。这是通过 RMI 提供的命名服务(RMI 注册中心)来查找远程对象,来接收作为返回值的引用。Java RMI 在概念上类似于 RPC,但能在不同地址空间支持对象调用的语义。
与大多数其他诸如 CORBA 的 RPC 系统不同,RMI 只支持基于 Java 来构建,但也正是这个原因, RMI 对于语言来说更加整洁,无需做额外的数据序列化工作。Java RMI 的设计目标应该是:
- 能够适应语言、集成到语言、易于使用;
- 支持无缝的远程调用对象;
- 支持服务器到 applet 的回调;
- 保障 Java 对象的安全环境;
- 支持分布式垃圾回收;
- 支持多种传输。
分布式对象模型与本地 Java 对象模型相似点在于:
- 引用一个对象可以作为参数传递或作为返回的结果;
- 远程对象可以投到任何使用 Java 语法实现的远程接口的集合上;
- 内置 Java instanceof 操作符可以用来测试远程对象是否支持远程接口。
不同点在于:
- 远程对象的类是与远程接口进行交互,而不是与这些接口的实现类交互;
- Non-remote 参数对于远程方法调用来说是通过复制,而不是通过引用;
- 远程对象是通过引用来传递,而不是复制实际的远程实现;
- 客户端必须处理额外的异常。
接口和类
所有的远程接口都继承自 java.rmi.Remote
接口。例如:
public interface bankaccount extends Remote
{
public void deposit(float amount)
throws java.rmi.RemoteException;
public void withdraw(float amount)
throws OverdrawnException,
java.rmi.RemoteException;
}
注意,每个方法必须在 throws 里面声明 java.rmi.RemoteException
。 只要客户端调用远程方法出现失败,这个异常就会抛出。
远程对象类
Java.rmi.server.RemoteObject
类提供了远程对象实现的语义包括hashCode、equals 和 toString。 java.rmi.server.RemoteServer
及其子类提供让对象实现远程可见。java.rmi.server.UnicastRemoteObject
类定义了客户机与服务器对象实例建立一对一的连接.
存根
Java RMI 通过创建存根函数来工作。存根由 rmic 编译器生成。自 Java 1.5 以来,Java 支持在运行时动态生成存根类。编译器 rmic 会提供各种编译选项。
定位对象
引导名称服务提供了用于存储对远程对象的命名引用。一个远程对象引用可以存储使用类 java.rmi.Naming
提供的基于 URL 的方法。例如,
BankAccount acct = new BankAcctImpl();
String url = "rmi://java.sun.com/account";
// bind url to remote object
java.rmi.Naming.bind(url, acct);
// look up account
acct = (BankAccount)java.rmi.Naming.lookup(url);
[外链图片转存失败(img-wb7nHblJ-1569411423003)(http://waylau.com/images/post/20160630-rpc-rmi_flow.png)]
图7 Java RMI 工作流程
RMI 架构
RMI 是一个三层架构(图8)。最上面是 Stub/Skeleton layer(存根/骨架层)。方法调用从 Stub、Remote Reference Layer (远程引用层)和 Transport Layer(传输层)向下,传递给主机,然后再次经传 Transport Layer 层,向上穿过 Remote Reference Layer 和 Skeleton ,到达服务器对象。 Stub 扮演着远程服务器对象的代理的角色,使该对象可被客户激活。Remote Reference Layer 处理语义、管理单一或多重对象的通信,决定调用是应发往一个服务器还是多个。Transport Layer 管理实际的连接,并且追踪可以接受方法调用的远程对象。服务器端的 Skeleton 完成对服务器对象实际的方法调用,并获取返回值。返回值向下经 Remote Reference Layer 、服务器端的 Transport Layer 传递回客户端,再向上经 Transport Layer 和 Remote Reference Layer 返回。最后,Stub 程序获得返回值。
要完成以上步骤需要有以下几个步骤:
- 生成一个远程接口;
- 实现远程对象(服务器端程序);
- 生成 Stub 和 Skeleton(服务器端程序);
- 编写服务器程序 ;
- 编写客户程序 ;
- 注册远程对象;
- 启动远程对象
[外链图片转存失败(img-tRQOdDEw-1569411423004)(http://waylau.com/images/post/20160630-rpc-rmi_logical.png)]
图8 Java RMI 架构
RMI 分布式垃圾回收
根据 Java 虚拟机的垃圾回收机制原理,在分布式环境下,服务器进程需要知道哪些对象不再由客户端引用,从而可以被删除(垃圾回收)。在 JVM中,Java 使用引用计数。当引用计数归零时,对象将会垃圾回收。在RMI,Java 支持两种操作:dirty 和 clean。本地 JVM 定期发送一个 dirty 到服务器来说明该对象仍在使用。定期重发 dirty 的周期是由服务器租赁时间来决定的。当客户端没有需要更多的本地引用远程对象时,它发送一个 clean 调用给服务器。不像 DCOM,服务器不需要计算每个客户机使用的对象,只是简单的做下通知。如果它租赁时间到期之前没有接收到任何 dirty 或者 clean 的消息,则可以安排将对象删除。
第三代 RPC 以及 Web Services
由于互联网的兴起,Web 浏览器成为占主导地位的用于访问信息的模型。现在的应用设计的首要任务大多数是提供用户通过浏览器来访问,而不是编程访问或操作数据。
网页设计关注的是内容。解析展现方面往往是繁琐的。传统 RPC 解决方案可以工作在互联网上,但问题是,他们通常严重依赖于动态端口分配,往往要进行额外的防火墙配置。
Web Services 成为一组协议,允许服务被发布、发现,并用于技术无关的形式。即服务不应该依赖于客户的语言、操作系统或机器架构。
Web Services 的实现一般是使用 Web 服务器作为服务请求的管道。客户端访问该服务,首先是通过一个 HTTP 协议发送请求到服务器上的 Web 服务器。Web 服务器配置识别 URL 的一部分路径名或文件名后缀并将请求传递给特定的浏览器插件模块。这个模块可以除去头、解析数据(如果需要),并根据需要调用其他函数或模块。对于这个实现流,一个常见的例子是浏览器对于 Java Servlet 的支持。HTTP 请求会被转发到 JVM 运行的服务端代码来执行处理。
XML-RPC
XML-RPC 是1998年作为一个 RPC 消息传递协议,将请求和响应封装解析为人类可读的 XML格式。XML 格式基于 HTTP 协议,缓解了传统企业的防火墙需要为 RPC 服务器应用程序打开额外的端口的问题。
下面是一个 XML-RPC 消息的例子:
<methodCall>
<methodName>
sample.sumAndDifference
</methodName>
<params>
<param><value><int> 5 </int></value></param>
<param><value><int> 3 </int></value></param>
</params>
</methodCall>
这个例子中,方法 sumAndDifference 有两个整数参数 5 和 3。
XML-RPC 支持的基本数据类型是:int、string、boolean、double 和 dateTime.iso8601。此外,还有 base64 类型用于编码任意二进制数据。array 和 struct 允许定义数组和结构。
XML-RPC 不限制语任何特定的语言,也不是一套完整的软件来处理远程过程,诸如存根生成、对象管理和服务查找都不在协议内。现在有很多库针可以针对不同的语言,比如 Apache XML-RPC 可以用于 Java、Python 和 Perl。
XML-RPC 是一个简单的规范(约7页),没有雄心勃勃的目标——它只关注消息,而并不处理诸如垃圾收集、远程对象、远程过程的名称服务和其他方面的问题。然而,即使没有广泛的产业支持,简单的协议却能广泛采用。
SOAP
SOAP(Simple Object Access Protocol,简单对象访问协议),是以 XML-RPC 规范作为创建 SOAP 的依据,成立于1998年,获得微软和 IBM 的大力支持。该协议在创建初期只作为一种对象访问协议,但由于 SOAP 的发展,其协议已经不单只是用于简单的访问对象,所以这种 SOAP 缩写已经在标准的1.2版后被废止了。1.2版在2003年6月24日成为 W3C 的推荐版本。SOAP 指定 XML 作为无状态的消息交换格式,包括了 RPC 式的过程调用。
有关 SOAP 的标准可以参阅 https://www.w3.org/TR/soap/。
SOAP 只是一种消息格式,并未定义垃圾回收、对象引用、存根生成和传输协议。
下面是一个简单的例子:
<?xml version='1.0' ?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope">
<env:Header>
<m:reservation xmlns:m="http://travelcompany.example.org/reservation"
env:role="http://www.w3.org/2003/05/soap-envelope/role/next"
env:mustUnderstand="true">
<m:reference>uuid:093a2da1-q345-739r-ba5d-pqff98fe8j7d</m:reference>
<m:dateAndTime>2001-11-29T13:20:00.000-05:00</m:dateAndTime>
</m:reservation>
<n:passenger xmlns:n="http://mycompany.example.com/employees"
env:role="http://www.w3.org/2003/05/soap-envelope/role/next"
env:mustUnderstand="true">
<n:name>Åke Jógvan Øyvind</n:name>
</n:passenger>
</env:Header>
<env:Body>
<p:itinerary
xmlns:p="http://travelcompany.example.org/reservation/travel">
<p:departure>
<p:departing>New York</p:departing>
<p:arriving>Los Angeles</p:arriving>
<p:departureDate>2001-12-14</p:departureDate>
<p:departureTime>late afternoon</p:departureTime>
<p:seatPreference>aisle</p:seatPreference>
</p:departure>
<p:return>
<p:departing>Los Angeles</p:departing>
<p:arriving>New York</p:arriving>
<p:departureDate>2001-12-20</p:departureDate>
<p:departureTime>mid-morning</p:departureTime>
<p:seatPreference/>
</p:return>
</p:itinerary>
<q:lodging
xmlns:q="http://travelcompany.example.org/reservation/hotels">
<q:preference>none</q:preference>
</q:lodging>
</env:Body>
</env:Envelope>
其中<soap:Envelope>
是 SOAP 消息中的根节点,是 SOAP 消息中必须的部分。<soap:Header>
是 SOAP 消息中可选部分,是指消息头。<soap:Body>
是 SOAP 中必须部分,是指消息体。
上面例子的 SOAP 消息结构如下:
[外链图片转存失败(img-nZTVmi2d-1569411423004)(http://waylau.com/images/post/20160630-soap-message-structure.png)]
图9 SOAP 消息结构
SOAP 它只是提供了一个标准化的消息结构,为了实现它往往需要用 WSDL 来描述 Web Services 的方法。WSDL (Web Services Description Language) 是基于 XML 的一种用于描述 Web Services 以及如何访问 Web Services 的语言。
WSDL 文档包括以下几个部分:
- 类型(Types):定义了 Web Services 使用的数据类型;
- 消息(n/a):描述使用消息的数据元素或参数;
- 接口(Interface):描述服务提供的操作。这包括操作以及每个操作所使用的输入和输出消息;
- 绑定(Binding):为每个端口定义消息格式和协议细节。例如,它可以定义 RPC 式的消息;
- 服务(Service):系统功能相关的集合,包括其关联的接口、操作、消息等;
- 终点(Endpoint):定义了地址或者 Web Services 的连接点;
- 操作(Operation):定义了 SOAP 的动作,以及消息编码的方式。
下面是一个 WSDL 2.0 版本的例子:
<?xml version="1.0" encoding="UTF-8"?>
<description xmlns="http://www.w3.org/ns/wsdl"
xmlns:tns="http://www.tmsws.com/wsdl20sample"
xmlns:whttp="http://schemas.xmlsoap.org/wsdl/http/"
xmlns:wsoap="http://schemas.xmlsoap.org/wsdl/soap/"
targetNamespace="http://www.tmsws.com/wsdl20sample">
<documentation>
This is a sample WSDL 2.0 document.
</documentation>
<!-- Abstract type -->
<types>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="http://www.tmsws.com/wsdl20sample"
targetNamespace="http://www.example.com/wsdl20sample">
<xs:element name="request"> ... </xs:element>
<xs:element name="response"> ... </xs:element>
</xs:schema>
</types>
<!-- Abstract interfaces -->
<interface name="Interface1">
<fault name="Error1" element="tns:response"/>
<operation name="Get" pattern="http://www.w3.org/ns/wsdl/in-out">
<input messageLabel="In" element="tns:request"/>
<output messageLabel="Out" element="tns:response"/>
</operation>
</interface>
<!-- Concrete Binding Over HTTP -->
<binding name="HttpBinding" interface="tns:Interface1"
type="http://www.w3.org/ns/wsdl/http">
<operation ref="tns:Get" whttp:method="GET"/>
</binding>
<!-- Concrete Binding with SOAP-->
<binding name="SoapBinding" interface="tns:Interface1"
type="http://www.w3.org/ns/wsdl/soap"
wsoap:protocol="http://www.w3.org/2003/05/soap/bindings/HTTP/"
wsoap:mepDefault="http://www.w3.org/2003/05/soap/mep/request-response">
<operation ref="tns:Get" />
</binding>
<!-- Web Service offering endpoints for both bindings-->
<service name="Service1" interface="tns:Interface1">
<endpoint name="HttpEndpoint"
binding="tns:HttpBinding"
address="http://www.example.com/rest/"/>
<endpoint name="SoapEndpoint"
binding="tns:SoapBinding"
address="http://www.example.com/soap/"/>
</service>
</description>
Microsoft .NET Remoting
从微软的产品角度来看,可以说 .NET Remoting 就是 DCOM 的一种升级,它改善了很多功能,并极好的融合到 .NET 平台下。Microsoft .NET Remoting 提供了一种允许对象通过应用程序域与另一对象进行交互的框架。
.NET Remoting 提供了一种允许对象通过应用程序域与另一对象进行交互的框架。这种框架提供了多种服务,包括激活和生存期支持,以及负责与远程应用程序进行消息传输的通讯通道。格式化程序用于在消息通过通道传输之前,对其进行编码和解码。应用程序可以在注重性能的场合使用二进制编码,在需要与其他远程处理框架进行交互的场合使用 XML 编码。在从一个应用程序域向另一个应用程序域传输消息时,所有的 XML 编码都使用 SOAP 协议。出于安全性方面的考虑,远程处理提供了大量挂钩,使得在消息流通过通道进行传输之前,安全接收器能够访问消息和序列化流
.NET Remoting 对象
有三类对象可以配置为 .NET Remoting 对象。您可以根据应用程序的需要来选择对象类型:
- Single Call(单一调用对象):
Single Call 能且只能为一个请求提供服务。在需要对象完成的工作量有限的情况下 Single Call 非常有用。Single Call 对象通常不要求存储状态信息,并且不能在方法调用之间保留状态信息。但是,Single Call对象可以配置为负载平衡模式。 - Singleton Objects(单一元素对象):
Singleton Objects 可以为多个客户端提供服务,因此可以通过保存客户端调用的状态信息来实现数据共享。当客户端之间需要明确地共享数据,并且不能忽略创建和维护对象的开销时,这类对象非常有用。 - Client-Activated Objects (CAO,客户端激活的对象):
CAO 是服务器端的对象,将根据来自客户端的请求激活这些对象。这种激活服务器对象的方法与传统的 COM coclass 激活方法非常相似。当客户端使用“new”运算符提交对服务器对象的请求时,会向远程应用程序发送一个激活请求消息。随后,服务器创建被请求类的实例,并向调用它的客户端应用程序返回 ObjRef。然后,使用此 ObjRef 在客户端上创建代理。客户端的方法调用将在代理上执行。客户端激活的对象可以为特定的客户端(不能跨越不同的客户端对象)保存方法调用之间的状态信息。每个“new”调用都会向服务器类型的独立实例返回代理。
在 .NET Remoting 中,可以通过以下方式在应用程序之间传递对象:
- 作为方法调用中的参数,例如:
public int myRemoteMethod (MyRemoteObject myObj)
- 方法调用的返回值,例如:
public MyRemoteObject myRemoteMethod(String myString)
- 访问 .NET 组件的属性或字段得到的值,例如:
myObj.myNestedObject
对于 Marshal By Value (MBV,按值封送)的对象,当它在应用程序之间传递时,将创建一个完整的副本。
对于 Marshal By Reference (MBR,按引用封送)的对象,当它在应用程序之间传递时,将创建该对象的引用。当对象引用 (ObjRef) 到达远程应用程序后,将转变成“代理”返回给原始对象。
下面是一个简单 .NET Remoting 服务器对象的代码示例:
using System;
using System.Runtime.Remoting;
namespace myRemoteService
{
// Well Known Web Service object
public class myRemoteObject : MarshalByRefObject
{
// Method myRemoteMethod
public String myRemoteMethod(String s)
{
return "Hello World";
}
}
}
下面是客户端代码来访问这个对象:
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
using myRemoteService;
public class Client
{
public static int Main(string[] args)
{
ChannelServices.RegisterChannel(new HttpChannel());
// Create an instance of a myRemoteObject class
myRemoteObject myObj = ( myRemoteObject)Activator.GetObject(typeof(myRemoteObject),
"http://myHost:7021/host/myRemoteObject.soap");
myObj. myRemoteMethod ("Hello World");
return 0;
}
}
租用生存期
对于那些具有在应用程序之外传送的对象引用的对象,将创建一个租用。租用具有一个租用时间。如果租用时间为 0,则租用过期,对象就断开与 .NET Romoting 框架的连接。一旦 AppDomain 中的所有对象引用都被释放,则下次垃圾回收时,该对象将被回收。租用控制了对象的生存期。
对象有默认的租用阶段。当客户端要在同一服务器对象中维护状态时,可以通过许多方法扩展租用阶段,使对象继续生存:
- 服务器对象可以将其租用时间设置为无限,这样 Remoting 在垃圾回收时就不会回收此对象。
- 客户端可以调用
RemotingServices.GetLifetimeService
方法,从 AppDomain 的租用管理器获取服务器对象的租用。然后,客户端可以通过 Lease 对象调用 Lease.Renew 方法以延长租用。 - 客户端可用 AppDomain 的租用管理器为特定的租用注册负责人。当 Remoting 对象的租用过期时,租用管理器将通知负责人提出续租的申请。
- 如果设置了
ILease::RenewOnCallTime
属性,则每次调用 Remoting 对象时,都会用 RenewOnCallTime 属性指定的总时间更新租用。
集成 .NET Remoting 对象
.NET Remoting 对象可以集成在:
- 托管可执行项:
.NET Remoting 对象可以集成在任何常规的 .NET EXE 或托管服务中。 - .NET 组件服务:
.NET Remoting 对象可以集成在 .NET 组件服务基础结构中,以便利用各种 COM+ 服务,例如:事务、JIT 和对象池等。 - IIS : .NET Remoting 对象可以集成在 Internet Information Server (IIS) 中。默认情况下,集成在 IIS 中的 Remoting 对象通过 HTTP 通道接收消息。要在 IIS 中集成 Remoting 对象,必须创建一个虚拟的根,并将 remoting.config 文件复制到其中。包含 Remoting 对象的可执行文件或 DLL 应放在 IIS 根指向的目录下的 bin 目录中。需要注意的是,IIS 根名称应该与配置文件中指定的应用程序名称相同。当第一个消息到达应用程序时,Remoting 配置文件会自动加载。使用这种方法,可以提供 .NET Remoting 对象作为 Web 服务。
下面是一个 Remoting.cfg 文件的例子:
<configuration>
<system.runtime.remoting>
<application name="RemotingHello">
<service>
<wellknown mode="SingleCall"
type="Hello.HelloService, Hello"
objectUri="HelloService.soap" />
</service>
<channels>
<channel port="8000"
type="System.Runtime.Remoting.Channels.Http.HttpChannel,
System.Runtime.Remoting" />
</channels>
</application>
</system.runtime.remoting>
</configuration>
通道服务 (System.Runtime.Remoting.Channels)
.NET 应用程序和 AppDomain 之间使用消息进行通信。.NET 通道服务为这一通信过程提供了基础传输机制。
.NET 框架提供了 HTTP 和 TCP 通道,但是第三方也可以编写并使用自己的通道。默认情况下,HTTP 通道使用 SOAP 进行通信,TCP 通道使用二进制有效负载。
通过使用可以编写到集成混合应用程序中的自定义通道,可以插入通道服务(使用 IChannel)。
下面是一个加载通道服务的例子:
public class myRemotingObj
{
HttpChannel httpChannel;
TcpChannel tcpChannel;
public void myRemotingMethod()
{
httpChannel = new HttpChannel();
tcpChannel = new TcpChannel();
ChannelServices.RegisterChannel(httpChannel);
// Register the HTTP Channel
ChannelServices.RegisterChannel(tcpChannel);
// Register the TCP Channel
}
}
序列化格式化程序 (System.Runtime.Serialization.Formatters)
.NET 序列化格式化程序对 .NET 应用程序和 AppDomain 之间的消息进行编码和解码。在 .NET 运行时中有两个本地格式化程序,分别为二进制 (System.Runtime.Serialization.Formatters.Binary
) 和 SOAP (System.Runtime.Serialization.Formatters.Soap
)。
通过实现 IRemotingFormatter 接口,并将其插入到上文介绍的通道中,可以插入序列化格式化程序。这样,您可以灵活地选择通道和格式化程序的组合方式,采用最适合应用程序的方案。
例如:您可以采用 HTTP 通道和二进制格式化程序(串行化二进制数据),也可以采用 TCP 通道和 SOAP 格式。
Remoting 上下文
上下文是一个包含共享公共运行时属性的对象的范围。某些上下文属性的例子是与同步和线程紧密相关的。当 .NET 对象被激活时,运行时将检查当前上下文是否一致,如果不一致,将创建新的上下文。多个对象可以同时在一个上下文中运行,并且一个 AppDomain 中可以有多个上下文。
一个上下文中的对象调用另一个上下文中的对象时,调用将通过上下文代理来执行,并且会受组合的上下文属性的强制策略影响。新对象的上下文通常是基于类的元数据属性选择的。
可以与上下文绑定的类称作上下文绑定类。上下文绑定类可以具有称为上下文属性的专用自定义属性。上下文属性是完全可扩展的,您可以创建这些属性并将它们附加到自己的类中。与上下文绑定的对象是从 System.ContextBoundObject
导出的。
.NET Remoting 元数据和配置文件
元数据
.NET 框架使用元数据和程序集来存储有关组件的信息,使得跨语言编程成为可能。.NET Remoting 使用元数据来动态创建代理对象。在客户端创建的代理对象具有与原始类相同的成员。但是,代理对象的实现仅仅将所有请求通过 .NET Remoting 运行时转发给原始对象。序列化格式化程序使用元数据在方法调用和有效负载数据流之间来回转换。
客户端可以通过以下方法获取访问 Remoting 对象所需的元数据信息:
- 服务器对象的 .NET 程序集 : 服务器对象可以创建元数据程序集,并将其分发给客户端。在编译客户端对象时,客户端对象可以引用这些程序集。在客户端和服务器都是托管组件的封闭环境中,这种方法非常有用。
- Remoting 对象可以提供 WSDL文件,用于说明对象及其方法。所有可以根据 WSDL 文件读取和生成 SOAP 请求的客户端都可以调用此对象,或使用 SOAP 与之通信。使用与 .NET SDK 一同分发的 SOAPSUDS.EXE 工具,.NET Remoting 服务器对象可以生成具有元数据功能的 WSDL 文件。当某个组织希望提供所有客户都能访问和使用的公共服务时,这种方法非常有用。
- .NET 客户可以使用 SOAPSUDS 工具从服务器上下载 XML 架构(在服务器上生成),生成仅包含元数据(没有代码)的源文件或程序集。您可以根据需要将源文件编译到客户端应用程序中。如果多层应用程序中某一层的对象需要访问其他层的 Remoting 对象,则经常使用此方法。
配置文件
配置文件(.config 文件)用于指定给定对象的各种 Remoting 特有信息。通常情况下,每个 AppDomain 都有自己的配置文件。使用配置文件有助于实现位置的透明性。配置文件中指定的详细信息也可以通过编程来完成。使用配置文件的主要好处在于,它将与客户端代码无关的配置信息分离出来,这样在日后更改时仅需要修改配置文件,而不用编辑和重新编译源文件。.NET Remoting 的客户端和服务器对象都使用配置文件。
典型的配置文件包含以下信息及其他信息:
- 集成应用程序信息
- 对象名称
- 对象的 URI
- 注册的通道(可以同时注册多个通道)
- 服务器对象的租用时间信息
下面是一个配置文件示例:
<configuration>
<system.runtime.remoting>
<application name="HelloNew">
<lifetime leaseTime="20ms" sponsorshipTimeout="20ms"
renewOnCallTime="20ms" />
<client url="http://localhost:8000/RemotingHello">
<wellknown type="Hello.HelloService, MyHello"
url="http://localhost:8000/RemotingHello/HelloService.soap" />
<activated type="Hello.AddService, MyHello"/>
</client>
<channels>
<channel port="8001"
type="System.Runtime.Remoting.Channels.Http.HttpChannel,
System.Runtime.Remoting" />
</channels>
</application>
</system.runtime.remoting>
</configuration>
.NET Remoting 方案
了解 .NET Remoting 如何工作之后,让我们来看一下各种方案,分析如何在不同的方案中充分发挥 .NET Remoting 的优势。下表列出了可能的客户端/服务器组合,以及默认情况下采用的底层协议和有效负载。请注意,.NET Remoting 框架是可扩展的,您可以编写自己的通信通道和序列化格式化程序。
客户端 | 服务器 | 有效负载 | 协议 |
---|---|---|---|
.NET 组件 | .NET 组件 | SOAP/XML | http |
.NET 组件 | .NET 组件 | 二进制 | TCP |
托管/非托管 | .NET Web 服务 | SOAP/XML | http |
.NET 组件 | 非托管的传统 COM 组件 | NDR(网络数据表示形式) | DCOM |
非托管的传统 COM 组件 | .NET 组件 | NDR | DCOM |
使用 HTTP-SOAP
Web 服务是可以通过 URL 寻址的资源,并通过编程向需要使用这些资源的客户端返回信息。客户端使用 Web Services 时不必考虑其实现细节。Web Services 使用称为“合约”的严格定义的接口,此接口采用 Web 服务说明语言 (WSDL) 文件描述。
.NET Remoting 对象可以集成在 IIS 中,作为 Web 服务提供。任何可以使用 WSDL 文件的客户端都可以按照 WSDL 文件中指定的合约,对 Remoting 对象执行 SOAP 调用。IIS 使用 ISAPI 扩展将这些请求路由到相应的对象。这样,Remoting 对象就可以作为 Web 服务对象来使用,从而充分发挥 .NET 框架基础结构的作用。如果您希望不同平台/环境的程序均能够访问对象,可以采用这种配置。这种配置便于客户端通过防火墙访问您的 .NET 对象。
[外链图片转存失败(img-VVOJCNGE-1569411423005)(http://waylau.com/images/post/20160630-remoting-http-soap.gif)]
图10 .NET 使用 HTTP-SOAP
使用 SOAP-HTTP 通道
默认情况下,HTTP 通道使用 SOAP 格式化程序。因此,如果客户端需要通过 Internet 访问对象,可以使用 HTTP 通道。因为这种方法使用 HTTP,所以此配置允许通过防火墙远程访问 .NET 对象。只需要按前一节中介绍的方法将这些对象集成在 IIS 中,即可将它配置为 Web 服务对象。随后,客户端就可以读取这些对象的 WSDL 文件,使用 SOAP 与 Remoting 对象通信。
使用 TCP 通道
默认情况下,TCP 通道使用二进制格式化程序。此格式化程序以二进制格式对数据进行序列化,并使用原始 socket 在网络中传送数据。如果对象部署在受防火墙保护的封闭环境中,此方法是理想的选择。这种方法使用 socket 在对象之间传递二进制数据,因此性能极佳。由于它使用 TCP 通道来提供对象,因此在封闭环境中具有低开销的优点。由于防火墙和配置的问题,此方法不宜在 Internet 上使用。
[外链图片转存失败(img-C8xN2Uqh-1569411423006)(http://waylau.com/images/post/20160630-remoting-tcp-channel.gif)]
图11 .NET 使用 TCP 通道
使用非托管的 COM 组件
可以通过 COM Interop Service 调用非托管的传统 COM 组件。当 .NET Remoting 客户端对象创建 COM 对象的实例时,该对象通过运行时可调用包装程序 (RCW) 来提供。其中,RCW 担当真正的非托管对象的代理。对于 .NET 客户,这些包装程序看起来和 .NET 客户端的任何其他托管类一样。但实际上,它们仅仅是托管 (.NET) 和非托管 (COM) 代码之间的封送调用。
同样地,您可以将 .NET Remoting 服务器对象提供给传统 COM 客户端。当 COM 客户端创建 .NET 对象的实例时,该对象通过 COM 可调用包装程序 (CCW) 来提供。其中,CCW 担当真正的托管对象的代理。
这两种方案都使用 DCOM 通信。如果环境中既有传统的 COM 组件,又有 .NET 组件,那么这种互操作性将为您提供便利。
总结
Microsoft .NET 框架提供了强大、可扩展、独立于语言的框架,适合开发可靠、可伸缩的分布式系统。.NET Romoting 框架提供了根据系统需求进行远程交互的强大手段。.NET Remoting 实现了与 Web 服务的无缝集成,并提供了一种方法,可以提供 .NET 对象以供跨平台访问。
Java 中的 XML Web Services
Java RMI 与远程对象进行交互,其实现是需要基于 Java 的模型。此外,它没有使用 Web Services 和基于 HTTP 的消息传递。现在,已经出现了大量的软件来支持基于 Java 的 Web Services。JAX-WS (Java API for XML Web Services) 就是作为 Web Services 消息息和远程过程调用的规范。它允许一个调用基于Java的web服务使用Java RMI(即。,相对透明的程序员)。JAX-WS 的一个目标是平台互操作性。其 API 使用 SOAP 和WSDL。双方不需要 Java 环境。
创建一个 RPC 端点
在服务器端,进行下面的步骤来创建一个 RPC 端点:
- 定义一个接口(Java接口);
- 实现服务;
- 创建一个发布者,用于创建服务的实例,并发布一个服务名字。
在客户端:
- 创建一个代理(客户端存根)。wsimport 命令根据 WSDL 文档,创建一个客户机存根;
- 编写一个客户端,通过代理创建远程服务的一个实例(存根),调用它的方法。
JAX-RPC 执行流程如下:
- Java 客户机调用存根上的方法(代理);
- 存根调用适当的 Web 服务;
- Web 服务器被调用并指导 JAX-WS 框架;
- 框架调用实现;
- 实现返回结果给该框架;
- 该框架将结果返回给 Web 服务器;
- 服务器将结果发送给客户端存根;
- 客户端存根返回信息给调用者;
[外链图片转存失败(img-SNn6RIFQ-1569411423006)(http://waylau.com/images/post/20160630-rpc-jax-ws_flow.png)]
图12 JAX-WS 调用流程
超越 SOAP
SOAP 虽然仍然是广泛部署应用,但在许多环境中很多厂商已经抛弃了 SOAP,转而使用其他更轻量、更容易理解、或者与 Web 交互模型更干净的机制。例如,Google 的 API 在2006年后就不再支持 SOAP 接口,而是使用AJAX、XML-RPC 和 REST 作为替代。一个匿名的微软员工批评 SOAP 过于复杂,因为“我们希望我们的工具来阅读它,而不是人”。不管上述言论是否准确,有一点是可以肯定的,SOAP 显然是一个复杂和高度冗长的格式。
AJAX
Web 浏览器最初的设计,是为 Web 页面提供非动态的交互模型。Web 浏览器是建立在同步的请求-响应(request-response)的交互模型。发送一个请求到服务器,服务器返回整个页面。在当时没有更新部分页面的好方法,而唯一可行的方法是利用帧,即将不同的页面加载到每一帧,其实现是笨重的,也有很大的限制性。而改变了这一切的关键因素是:
- 文档对象模型(Document Object Model)和 JavaScript 的出现,使得可以以编程方式来更改 Web 页面的各个部分;
- AJAX 提供了与服务器以非阻塞方式进行交互,即允许底层 JavaScript 在等待服务器结果时,用户仍然可以与页面进行交互。
AJAX 全称是 Asynchronous JavaScript And XML(异步的 JavaScript 和 XML)。让我们看看这些三项:
- 它是异步的,因为客户端等待服务器结果不会被阻塞;
- AJAX 集成到了 JavaScript,作为浏览器解释 Web 页面的一部分。JavaScript 使用 HTTPRequest 来调用 AJAX 请求。JavaScript 也可能修改文档对象模型,定义了页面的样子;
- 数据以 XML 文档形式发送和接收。(在后期发展中,AJAX 也支持其他的数据格式,比如 JSON)
AJAX 在推动 Web 2.0 的过程中发挥了重要的,比如产生了很多高度交互的服务,如Google Maps、Writely等。基本上,它允许 JavaScript 发出HTTP 请求,获取和处理结果,刷新局部页面元素而不是整个页面。在大多数浏览器请求的格式如下:
new XMLHttpRequest()
xmlhttp.open(“HEAD”, “index.html”, true)Tell object:
REST
SOAP 在创建自己的消息传递协议时是基于HTTP,但实际上 REST (REpresentational State Transfer) 的方式才是保持 Web 的原理和使用 HTTP 协议的核心部分。
原始的 HTTP 协议已经定义了四个命令,清晰地映射到各种数据(定义为“资源”)操作:
- PUT (插入)
- GET (选择)
- POST (更新)
- DELETE (删除)
REST 其背后的理念是使用这些 HTTP 命令来请求和操作数据。作为 HTTP协议的一部分,REST 使用 URL 来引用对象和操作。考虑这个 HTTP 操作列表的例子:
HTTP GET //www.waylau.com/parts
这个命令将返回一个 XML 文档,其中包含部分的列表。注意,返回的不是一个网页,只是一个包含所请求的数据 XML 数据结构。
<?xml version="1.0"?>
<p:Parts xmlns:p="http://www.waylau.com"
xmlns:xlink="http://www.w3.org/1999/xlink">
<Part id="00345" xlink:href="http://www.waylau.com/parts/00345"/>
<Part id="00346" xlink:href="http://www.waylau.com/parts/00346"/>
<Part id="00347" xlink:href="http://www.waylau.com/parts/00347"/>
<Part id="00348" xlink:href="http://www.waylau.com/parts/00348"/>
</p:Parts>
要特定部分的详细信息,发送一个HTTP get 命令:
HTTP GET //www.waylau.com/parts/00345
这将返回一个特定的信息部分:
<?xml version="1.0"?>
<p:Part xmlns:p="http://www.waylau.com"
xmlns:xlink="http://www.w3.org/1999/xlink">
<Part-ID>00345</Part-ID>
<Name>Widget-A</Name>
<Description>This part is used within the frap assembly</Description>
<Specification xlink:href="http://www.waylau.com/parts/00345/specification"/>
<UnitCost currency="USD">0.10</UnitCost>
<Quantity>10</Quantity>
</p:Part>
注意,上面例子简化了 partid 作为 URL 的参数。例如:
HTTP GET //www.waylau.com/parts?partid=00345
REST 不是 RPC,但也有类似的请求-响应模式。制定透明度请求、封送数据、解析响应这些不属于 REST。REST 应用非常广泛,如 Yahoo! Search API、Ruby on Rails、Twiter 和 Open Zing Services 等。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
<Description>This part is used within the frap assembly</Description>
<Specification xlink:href="http://www.waylau.com/parts/00345/specification"/>
<UnitCost currency="USD">0.10</UnitCost>
<Quantity>10</Quantity>
</p:Part>
注意,上面例子简化了 partid 作为 URL 的参数。例如:
HTTP GET //www.waylau.com/parts?partid=00345
REST 不是 RPC,但也有类似的请求-响应模式。制定透明度请求、封送数据、解析响应这些不属于 REST。REST 应用非常广泛,如 Yahoo! Search API、Ruby on Rails、Twiter 和 Open Zing Services 等。
[外链图片转存中...(img-ua7BB6uK-1715715832031)]
[外链图片转存中...(img-2QszDfCp-1715715832031)]
**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**[需要这份系统化的资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618636735)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**