第5章分布式系统模式 使用服务器激活对象通过 .NET Remoting 实现 Broker

正在使用 Microsoft? .NET Framework 构建一个需要使用分布式对象的应用程序。您的要求包括能够按值或按引用来传递对象,无论这些对象驻留在同一台计算机上,还是驻留在同一个局域网 (LAN) 中的不同计算机上,或者是驻留在广域网 (WAN) 中的不同计算机上。应用程序不需要您显式控制远程对象的生存期。

关于 .NET Remoting 的背景信息

远 程处理使用对象引用来进行客户端和服务器之间的通信。在服务器激活情况下,客户端使用远程处理基础结构 (Activator.GetObject) 来检索对现有服务器对象的引用。有了对象的引用后,就可以调用对象的方法,就好像该对象在您的进程中,而没有运行在不同的计算机上。以下基础机制用于实现 该功能:

  • 客户端检索远程类型的实例。
  • 远程处理基础结构创建一个充当远程类型的代理对象。
  • 客户端调用该代理的方法。远程处理系统收到调用、将其路由到服务器进程、调用服务器对象,然后将结果返回给客户端代理,客户端代理再将结果传递给客户端对象。

调 用本身必须以某种方式在客户端和服务器之间进行发送。远程处理基础结构将该机制称为传输通道。通道在应用程序之间跨越远程处理边界传输消息,无论这种边界 是应用程序域之间、进程之间还是计算机之间的边界。通道可以在端点上侦听入站消息;将出站消息发送到另一个端点,或者同时执行这两个任务。这样,您就可以 插入各种协议,即使公共语言运行库不在通道的另一端。

虽然服务器进程知道关于每个唯一对象的一切信息,但客户端只知道它需要引用另一个应用程序域中的某个对象(可能在另一个计算机上)。从服务器应用程序域之外的范围来看,该对象是通过 URL 定位的。

服务器激活

正如分布式系统群集的介绍中描述的那样,.NET Framework 支持两种激活模型:服务器激活和客户端激活。服务器激活对象是其生存期直接由服务器控制的对象。只有当客户端调用对象的方法时,而不是在客户端调用 newActivator.GetObject() 时,服务器应用程序域才会创建这些对象;这样可以减少只是为了创建实例而发生的网络往返通信。当客户端请求一个服务器激活类型的实例时,只会在客户端应用 程序域中创建一个代理。不过,这还意味着服务器激活类型只允许有默认的构造函数。如果要发布的类型的实例将以需要接受参数的特定构造函数来创建,那么,可 以使用客户端激活。

为了创建服务器激活类型的实例,客户端通常使用 Activator.GetObject().

选择协议和序列化机制

您 选择的协议类型会影响应用程序执行的方式。有关为应用程序选择正确的通道类型的某些标准,请参阅《.NET Framework Developer‘s Guide》中的“Choosing Communication Options in .NET”主题,您可以访问 MSDN? 开发人员程序网站:http://msdn.microsoft.com/library/ 来了解有关内容。

在此模式中,您将看到 HttpChannel/SOAP 和 TcpChannel/Binary 这两个示例。

实现策略

该模式提供了服务器激活对象的两个示例,以及 .NET Remoting 基础结构的灵活性。第一个示例使用 HttpChannel 及其默认的序列化机制 SOAP。第二个示例使用 TcpChannel 及其默认的二进制序列化机制。在讨论应用程序本身之前,我们首先要了解必须在整个网络中分布的类。

服务器对象

RecordingsManager 类有一个名为 GetRecordings 的方法,它从数据库中检索一列记录,然后在 DataSet 中返回结果。注意,在确定要通过远程连接传输的最佳数据类型时,会涉及到一系列考虑因素。该示例使用 DataSet,因为它的示例代码很简短,并且显示了复杂数据类型是如何传送的。有关本主题的深入探讨,请参阅 MSDN 文章“Designing Data Tier Components and Passing Data Through Tiers”:

http://msdn.microsoft.com/library/en-us/dnbda/html/BOAGag.asp

RecordingsManager.cs

以下示例显示了 RecordingsManager 类:

using System;

using System.Data;

using System.Data.SqlClient;

public class RecordingsManager

{

public DataSet GetRecordings()

{

String selectCmd = "select * from Recording";

SqlConnection myConnection = new SqlConnection(

"server=(local);database=recordings;Trusted_Connection=yes");

SqlDataAdapter myCommand =

new SqlDataAdapter(selectCmd, myConnection);

DataSet ds = new DataSet();

myCommand.Fill(ds, "Recording");

return ds;

}

}

必须以远程方式访问该类。首先,RecordingsManager 类必须从名为 MarshallByRefObject 的远程处理基础结构中的一个类继承而来。MarshalByRefObject 是那些通过使用代理交换消息来跨越应用程序域边界进行通信的对象的基类。不是从 MarshalByRefObject 继承的对象会以隐式方式按值封送。当远程应用程序引用一个按值封送的对象时,将跨越远程处理边界传递该对象的副本。因为您希望使用代理方法而不是副本方法进行通信,因此需要继承 MarshallByRefObject。其次,您需要从该类提取一个接口。接口对于减少客户端和服务器之间的依赖性是必不可少的,另外,也可以更好地部署应用程序。有关详细信息,请参阅该模式后面的“部署考虑事项”。

IRecordingsManager.cs

以下是提取的 IRecordingsManager 接口的代码:

using System;

using System.Data;

public interface IRecordingsManager

{

DataSet GetRecordings();

}

RecordingsManager.cs (启用远程支持)

更改 RecordingsManager 后得到以下代码:

public class RecordingsManager : MarshalByRefObject, IRecordingsManager

{ /*  */ }

HttpChannel:SOAP 序列化

选择此通道和序列化机制的主要动机是安全性和互操作性。通过以 Microsoft Internet 信息服务 (IIS) 为宿主的 HttpChannel,可以利用内置在 IIS 和 ASP.NET 中的安全功能。如果您选择任何其他通道,或选择 HttpChannel 不驻留在 IIS 中,则必须提供自己的安全功能。另外,为了实现不同操作系统之间的互操作,必须使用 HttpChannel 和 SOAP 序列化。不过,由于使用了 XML 序列化以及在 IIS 和 ASP.NET 内使用 HTTP 协议而需要额外的系统开销,选择 HttpChannel 并不能获得最高性能。有关详细信息,请参阅此模式后面的“操作考虑事项”。

以下解决方案将 HttpChannel 以及 SOAP 序列化用于前面描述的 RecordingsManager 类(请参阅图 1)。

1 HttpChannel 实现

HttpServer.cs

HttpServer 是一个控制台应用程序,该程序创建了 HttpChannel 对象并分配端口 8100。然后,代码将名称“RecordingsManager.soap”与一个 RecordingsManager 实例相关联。

服务器激活对象有两种激活模式:SingletonSingleCall

Singleton 类型在任何时刻只能有一个实例。如果实例已存在,则所有客户端请求都由该实例来处理。如果不存在实例,服务器将创建一个实例,并且所有随后的客户端请求都会由该实例来处理。

SingleCall 类型对于每个客户端请求始终有一个实例。下一个方法调用将由其他服务器实例来处理,即使前一个实例尚未被系统回收。

RecordingsManager 使用 Singleton 激活模式,因此只有一个 RecordingsManager 实例运行在服务器上。这个过程很有效,因为对象只有一个方法来检索一组预定义数据。最后一行确保用户按下 Enter 键之后代码才退出。请注意,也许这不是确保程序不退出的最佳方式。如果程序退出,客户端将无法访问服务器对象。

using System;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Http;

public class HttpServer

{

static void Main(string[] args)

{

HttpChannel channel = new HttpChannel(8100);

ChannelServices.RegisterChannel(channel);

RemotingConfiguration.RegisterWellKnownServiceType(

typeof(RecordingsManager),

"RecordingsManager.soap",

WellKnownObjectMode.Singleton);

Console.ReadLine();

}

}

HttpClient.cs

客户端程序调用远程处理框架函数 Activator.GetObject(),从而指定对象所在的 URL 以及应该返回的类型。在本示例中的情况下,IRecordingsManager 对象应该在 http://localhost:8100/RecordingsManager.soap。有了实例之后,可以调用实例的方法,就好像它在同一个应用程序域中。

using System;

using System.Data;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Http;

public class HttpClient

{

[STAThread]

static void Main(string[] args)

{

HttpChannel channel = new HttpChannel();

ChannelServices.RegisterChannel(channel);

IRecordingsManager mgr = (IRecordingsManager)

Activator.GetObject(typeof(IRecordingsManager),

"http://localhost:8100/RecordingsManager.soap");

Console.WriteLine("Client.main(): Reference acquired");

DataSet ds = mgr.GetRecordings();

Console.WriteLine("Recordings Count: {0}",

ds.Tables["recording"].Rows.Count);

}

}

TcpChannel:二进制序列化

选择此通道和序列化机制的主要动机是性能。实际上,使用二进制序列化就能显著提高性能。(请参阅“操作考虑事项”。)如果没有任何安全问题(例如,您正在构建一个完全运行在防火墙内的小应用程序),应该使用 TcpChannel 和二进制序列化,因为这样会获得最佳性能。

以下解决方案将 TcpChannel 以及二进制序列化用于前面描述的 RecordingsManager 类(请参阅图 2)。

2 TcpChannel/ 二进制序列化实现

TcpServer.cs

TcpServer 是一个控制台应用程序,它创建 TcpChannel 对象并分配端口 8100。然后,代码将名称“GetRecordingsManager”与一个 RecordingsManager 实例相关联。RecordingsManager 的激活模式是 Singleton,因此只会有一个 RecordingsManager 实例运行在服务器上。最后一行确保用户按下 Enter 键之后代码才退出。请注意,也许这不是确保程序不退出的最佳方式。如果程序退出,客户端将无法访问服务器对象。

using System;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Tcp;

public class TcpServer

{

static void Main(string[] args)

{

TcpChannel channel = new TcpChannel(8100);

ChannelServices.RegisterChannel(channel);

RemotingConfiguration.RegisterWellKnownServiceType(

typeof(RecordingsManager),

"GetRecordingsManager",

WellKnownObjectMode.Singleton);

Console.ReadLine();

}

}

TcpClient.cs

客户端程序通过调用远程处理框架方法 Activator.GetObject(),以便在服务器上检索 RecordingsManager 对象的代理。该方法指定对象所在的 URL 以及应该返回的类型。在本示例的情况下,IRecordingsManager 对象应该位于:http://localhost:8100/GetRecordingsManager。有了实例后,可以调用该实例的方法,就好像它在同一个应用程序域中。

using System;

using System.Data;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Tcp;

class TcpClient

{

[STAThread]

static void Main(string[] args)

{

TcpChannel channel = new TcpChannel();

ChannelServices.RegisterChannel(channel);

IRecordingsManager mgr = (IRecordingsManager)

Activator.GetObject(typeof(IRecordingsManager),

"tcp://localhost:8100/GetRecordingsManager");

Console.WriteLine("Client.main(): Reference acquired");

DataSet ds = mgr.GetRecordings();

Console.WriteLine("Recordings Count: {0}",

ds.Tables["recording"].Rows.Count);

}

}

部署考虑事项

使用 .NET Remoting 时,必须在将应用程序部署到不同的程序集中时多加小心。主要目标是要确保服务器上的代码不会传送到客户端。图 3 是 HttpChannel/SOAP 示例的 UML 部署图。

3 HttpChannel/SOAP 示例的结构

该示例使用一个名为 IrecordingsManager 的程序集,该程序集由客户端和服务器共享。该程序集包含 IRecordingsManager 接口,它定义了客户端和服务器正在共享的远程对象的接口。在该示例中,IRecordingsManager 程序集被下载到客户端。

测试

用 Nunit 为服务器编写测试相对比较简单。可以从服务器检索对象,然后将这些对象当作本地对象调用它们的方法。下面的类测试 HttpServer 类:

HttpServerFixture.cs

using System;

using System.Data;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Http;

using NUnit.Framework;

[TestFixture]

public class HttpServerFixture

{

private IRecordingsManager mgr;

private HttpChannel channel;

private DataSet dataSet;

[SetUp]

public void LoadDataSet()

{

channel = new HttpChannel();

ChannelServices.RegisterChannel(channel);

mgr = (IRecordingsManager)

Activator.GetObject(typeof(IRecordingsManager),

"http://localhost:8100/RecordingsManager.soap");

dataSet = mgr.GetRecordings();

}

[Test]

public void RetrieveDataSet()

{

DataTable recording = dataSet.Tables["recording"];

Assertion.AssertEquals(4,recording.Rows.Count);

DataRow row = recording.Rows[0];

string title = (string)row["title"];

Assertion.AssertEquals("Up", title.Trim());

}

[TearDown]

public void Release()

{

ChannelServices.UnregisterChannel(channel);

}

}

结果上下文

使用服务器激活对象通过 .NET Remoting 来实现 Broker 具有下列优缺点。

优点

.NET Remoting 为全功能的分布式对象模型提供了运行在客户端和服务器上的全公共语言运行库语义。客户端和服务器之间所传递的数据的保真度不会受任何影响。该示例显示了如 何在客户端和服务器之间传递复杂类型 System.Data.DataSet。如果连接的两端没有公共语言运行库,就不可能实现这样的传递。

缺点

有些 Broker 优点会受到以下潜在缺点的影响:

  • 远程对象。 您必须记住,这些对象是远程对象。即使它们看上去像是本地对象,但从服务器来回封送数据仍然需要开销。记住,远程调用比公共语言运行库中的本地调用至少慢 1000 倍。因此,您应当只在需要时才进行这样的调用。由于需要最大限度地减少往返操作,这可能导致您在处理接口时不会使用最细的粒度。
  • 部署的复杂性。使用示例中描述的服务器激活对象时,在客户端请求对象之前,必须已经注册了该对象。这会使部署变得更加复杂。
  • 有限的互操作性。 您可以使用 .NET Remoting 来构建 Web Service。不过,必须将端点限制为最简单的数据类型。例如,如果希望能够与其他 Web Service 工具包进行互操作,必须将参数限制为内置的简单类型和您自己的数据类型(不要使用 .NET Framework 类型,例如 DataSet),并且使用服务器激活对象。
  • 更加复杂。与 Web Service 相比,.NET Remoting 更难学习、实现和调试。

安全考虑事项

要 使用 Microsoft Internet 信息服务 (IIS) 所提供的安全功能(例如,标准 HTTP 身份验证方案,包括基本验证、摘要式验证、数字证书,甚至 Microsoft .NET Passport),您必须使用一个基于 HTTP 的应用程序,而且该应用程序应当驻留在具有 ASP.NET 环境的 IIS 中。如果要使用其他任何传输协议,或使用 IIS 之外的 HttpChannel,都需要您提供安全机制。

操作考虑事项

以 下是 MSDN文章“Performance Comparison: .NET Remoting vs. ASP.NET Web Services”(.NET Remoting 与. ASP.NET Web Service 的性能比较)[Dhawan02] 中的性能比较的概述。该文的结论是,通过使用 TCP 通道和二进制序列化以及 Windows 服务主机,您可以实现最高性能。这种配置通过原始 TCP 套接字传输二进制数据,这比 HTTP 更有效。与 HttpChannel(它使用驻留在具有 ASP.NET 的 IIS 中的 SOAP 序列化)这种最慢的方法相比,其性能快 60%。

驻留在 IIS 中会导致性能下降,因为它涉及从 IIS (Inetinfo.exe) 到 Aspnet_wp.exe 的额外进程跳跃。不过,如果选择在没有 IIS 和 ASP.NET 的情况下驻留您的通道,则需要提供您自己的身份验证、授权和隐私机制。

时间: 2024-10-19 12:08:33

第5章分布式系统模式 使用服务器激活对象通过 .NET Remoting 实现 Broker的相关文章

第5章分布式系统模式 使用客户端激活对象通过 .NET Remoting 实现 Broker

正在 .NET 中构建一个需要使用分布式对象的应用程序,并且分布式对象的生存期由客户端控制.您的要求包括能够按值或按引用来传递对象,无论这些对象驻留在同一台计算 机上,还是驻留在同一个局域网 (LAN) 中的不同计算机上,或者是驻留在广域网 (WAN) 中的不同计算机上. 实现策略 这 种模式为在 .NET Remoting 中实现客户端激活对象提供了两种实现方式.客户端激活对象 (CAO) 和服务器激活对象 (SAO) 之间的主要区别在于,是什么控制着远程对象的生存期.在使用 CAO 的情况下

第5章分布式系统模式

在当今的互联世界中,越来越多的企业应用程序跨多个服务器分布和运行.连接到远程数据源和 Web Service,并可通过 Internet 访问.分布式计算功能强大,但也并非没有面临挑战.网络在本质上并不可靠,同本地的进程间通信相比,与远程服务器的通信速度较慢.另外,同时在多台计算机 上运行一个程序可能会导致许多并发和同步问题. 基于实例的协作和基于服务的协议 按照 Business Component Factory(业务组件工厂)的说,分布式计算可以基于两个截然不同的体系结构样式: 基于实例的

第5章分布式系统模式 Broker(代理程序)

许多复杂的软件系统运行在多个处理器或分布式计算机上.将软件分布在多台计算机上的原因有多种,例如: 分布式系统可以利用多个 CPU 或一群低成本计算机的计算能力. 某个软件可能仅在特定计算机上可用. 出于安全考虑,软件的各部分可能必须运行在不同的网段上. 一些服务可能是由业务合作伙伴提供的,并且只能通过 Internet 进行访问. 但是,实现分布式系统是不容易的,因为您必须处理诸如并发性.跨平台连接和不可靠网络连接之类的问题. 影响因素 在构建分布式系统时,必须协调下列影响因素: 虽 然分布式系

第5章分布式系统模式 Data Transfer Object(数据传输对象)

正在设计一个分布式应用程序,为了满足单个客户端请求,您发现自己对一个远程接口发出了多个调用,而这些调用所增加的响应时间超出了可接受的程度. 影响因素 在与远程对象通信时,请考虑下列需要权衡的因素: 远程调用(那些必须跨越网络的调用)速度缓慢.虽然许多远程调用框架可以隐藏进行远程调用的复杂性,但是它们不能消除发生通信所需的步骤.例如,必须先找到 远程对象位置,而且建立与远程计算机的连接,然后才能将数据串行化为字节流,然后可能进行加密,最后才能将其传输到远程计算机. 在 考虑网络性能时,必须同时考虑

第5章分布式系统模式 Singleton

上下文 在某些情况下,特定类型的数据需要提供给应用程序中的其他所有对象使用.在大多数情况下,这种类型的数据在系统中还是唯一的.例如,用户界面只能有一个所有应用程序必须访问的鼠标指针.同样,企业解决方案可能用单网关对象作为接口来管理与特定旧系统的连接. 影响因素 以下因素影响这种情况中的系统,在考虑上述问题的解决方案时必须协调这些影响因素: 很多编程语言(例如 Microsoft Visual Basic® 6.0 版或 C++)都支持全局对象的定义.这些对象位于命名空间的根部,应用程序中所有对象

第5章分布式系统模式 在 .NET 中使用 DataSet 实现 Data Transfer Object

要在 .NET Framework 中实现分布式应用程序.客户端应用程序需要显示一个窗体,该窗体要求对 ASP.NET Web Service 进行多个调用以满足单个用户请求.基于性能方面的考虑,我们发现,进行多个调用会降低应用程序性能.为了提高性能,需要通过对 Web Service 进行一次调用就能检索到用户请求所需的所有数据. 背景信息 注意:以下是在 .NET 中使用类型化 DataSet 实现 Data Transfer Object 中所描述的同一个示例应用程序. 下面是一个简化的

使用Micrisoft.net设计方案 第二章组织模式

模式不仅依赖于它所包含的更小模式,同时也依赖包含它的更大的模式.它是描述复杂软件的系统方法. 本章的目标是让我们了解以下问题: 1.如何标识模式与模式的关系 2.如何把模式组织成模式集合 3.如何采用不同抽象级别去划分模式 4.如何使用模式解决系统中涉及到的各个方面 5.如何用模式描述解决方案 模式与模式 模式能够描述关系.采用面向对象设计的软件都是有类组成,如果抛开类与类间的关系,模式将什么问题也不能解决.模式把一组类组织成便于管理的模式集合. 我们设计系统时,会发现使用的模式比使用的类都多,

分布式系统卫星时钟服务器(NTP服务器)架设与设计

分布式系统卫星时钟服务器(NTP服务器)架设与设计 分布式系统卫星时钟服务器(NTP服务器)架设与设计 本文由安徽京准科技提供支持和原资料——更多阐述可参考微♥ ahjzsz  分布式系统由Tanenbaum定义,“分布式系统是一组独立的计算机,在”分布式系统?—?原理和范例“中作为用户的单一,连贯的系统出现”. 区块链通过构建全球分布式系统,尝试实现分散的新数据存储和组织结构. 首先,定位到分布式系统的原因主要是可扩展性,位置和可用性.区块链也不例外.地理可扩展性,形成全球价值存储网络/信息保

第四章 从远程rsync服务器同步数据

第四章 从远程rsync服务器同步数据 使用rsync从远程rsync服务器同步数据 第一节 rsync配置 拉:          rsync        选项         用户名@备份源服务器IP::共享模块名  目标目录 推:         rsync        选项         备份源目录   用户名@目标服务器IP::共享模块名 C/S模式: 服务端==>    远程服务器为:DataServer.  IP地址为:192.168.88.8 客户端==>    备份服务