65.9K
CodeProject 正在变化。 阅读更多。
Home

.NET Remoting 简明示例

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.91/5 (180投票s)

2006 年 7 月 13 日

23分钟阅读

viewsIcon

1052789

downloadIcon

44261

通过一个简单的示例解释 .NET Remoting

引言

.NET Remoting 是一种用于在不同进程中的对象之间进行通信的机制。它是一个通用的系统,用于不同应用程序之间的相互通信。.NET 对象被暴露给远程进程,从而实现进程间通信。应用程序可以位于同一台计算机上、同一网络中的不同计算机上,或者位于不同网络中的计算机上。

Microsoft .NET Remoting 提供了一个框架,允许对象跨应用程序域相互交互。Remoting 的设计方式隐藏了最困难的方面,如连接管理、数据封送处理以及 XML 和 SOAP 的读写。该框架提供了许多服务,包括对象激活和对象生命周期支持,以及负责将消息传输到远程应用程序和从远程应用程序传输消息的通信通道。

远程对象

什么是远程对象?任何位于调用应用程序的应用程序域之外的对象都应被视为远程对象,该对象将被重建。无法序列化的本地对象无法传递到不同的应用程序域,因此无法进行远程处理。

任何对象都可以通过从 MarshalByRefObject 派生,或者通过添加 [Serializable] 标记或实现 ISerializable 接口使其可序列化来转换为远程对象。当客户端激活远程对象时,它会收到远程对象的代理。对该代理的所有操作都会被适当地间接处理,以使 Remoting 基础设施能够适当地拦截和转发调用。在代理和远程对象位于不同应用程序域的情况下,堆栈上的所有方法调用参数都被转换为消息并传输到远程应用程序域,在那里消息被转换回堆栈帧并调用方法。返回方法调用的结果也使用相同的过程。

.NET 可远程处理对象的类型

有三种类型的对象可以配置为 .NET 远程对象。您可以根据应用程序的需求选择对象的类型。

单次调用

单次调用对象仅服务于一个传入请求。单次调用对象适用于需要完成有限工作的场景。单次调用对象通常不需要存储状态信息,并且它们无法在方法调用之间保持状态信息。

单例对象

单例对象是那些服务于多个客户端的对象,因此通过在客户端调用之间存储状态信息来共享数据。它们适用于需要在客户端之间显式共享数据,以及创建和维护对象的开销很大的情况。

客户端激活对象 (CAO)

客户端激活对象 (CAO) 是服务器端对象,它们在客户端请求时激活。当客户端使用“new”运算符提交服务器对象的请求时,会向远程应用程序发送激活请求消息。然后服务器创建请求类的实例,并将一个 ObjRef 返回给调用它的客户端应用程序。然后使用 ObjRef 在客户端创建代理。客户端的方法调用将在代理上执行。客户端激活对象可以为其特定客户端在方法调用之间存储状态信息,而不是跨不同的客户端对象。每次调用“new”都会返回一个独立服务器类型实例的代理。

域名

在 .NET 中,当应用程序加载到内存中时,会创建一个进程,并在此进程中创建一个应用程序域。应用程序实际上加载在应用程序域中。如果此应用程序与另一个应用程序通信,则必须使用 Remoting,因为另一个应用程序将拥有自己的域,并且跨域对象无法直接通信。不同的应用程序域可以存在于同一进程中,也可以存在于不同的进程中。

上下文

.NET 运行时进一步将应用程序域划分为上下文。上下文保证一组共同的约束和使用语义管理对其中所有对象的访问。除非另有指示,所有应用程序都有一个默认上下文,在其中构造对象。上下文,就像应用程序域一样,形成 .NET Remoting 边界。访问请求必须跨上下文进行封送处理。

代理

当在同一应用程序域中的对象之间进行调用时,只需要进行正常的本地调用;但是,跨应用程序域的调用需要进行远程调用。为了方便远程调用,.NET 框架在客户端引入了一个代理。此代理是 TransparentProxy 类的一个实例,直接可供客户端用于与远程对象通信。通常,代理对象是代表其他对象行事的对象。代理对象确保对代理进行的所有调用都转发到正确的远程对象实例。在 .NET Remoting 中,代理管理封送处理过程以及进行跨边界调用所需的其他任务。.NET Remoting 基础设施自动处理代理的创建和管理。

RealProxy 和 TransparentProxy

.NET Remoting 框架使用两个代理对象来完成从客户端对象到远程 服务器 对象的远程调用工作:一个 RealProxy 对象和一个 TransparentProxy 对象。RealProxy 对象负责实际向远程对象发送消息并从远程对象接收响应消息。TransparentProxy 与客户端交互,并负责拦截客户端发出的远程方法调用。

封送处理

对象封送处理指定远程对象如何暴露给客户端应用程序。它是将对象访问请求打包在一个应用程序域中并将其请求传递到另一个域的过程。.NET Remoting 基础设施管理整个封送处理过程。有两种方法可以将远程对象提供给本地客户端对象:按值封送和按引用封送。

按值封送对象

按值封送类似于在客户端拥有服务器对象的副本。按值封送的对象在远程服务器上创建,序列化为流,并传输到客户端,在那里重建一个精确的副本。一旦复制到调用方的应用程序域(通过封送处理过程),所有方法调用和属性访问都完全在该域内执行。

按值封送有几个含义;首先,整个远程对象通过网络传输。其次,远程对象的某些部分或全部可能在其本地上下文之外没有关联。例如,远程对象可能具有到数据库的连接,或到窗口的句柄,或文件句柄等。第三,远程对象的某些部分可能无法序列化。此外,当客户端调用 MBV 对象上的方法时,本地机器执行,这意味着编译的代码(远程类)必须可用于客户端。因为对象完全存在于调用方的应用程序域中,所以对象的状态更改不会传达给原始应用程序域,也不会从原始应用程序域传达回调用方。

但是,如果 MBV 对象很小,并且提供不消耗带宽的重复功能,则它们非常高效。整个对象存在于调用方的域中,因此无需跨域边界封送访问。当用于小对象或您将进行多次访问的对象时,使用按值封送对象可以提高性能并减少网络流量。

按值封送类必须用 [Serializable] 属性标记才能使用默认序列化,或者必须实现 ISerializable 接口。

按引用封送对象

按引用封送类似于拥有对象的指针。按引用封送将远程对象的引用传回给客户端。此引用是一个 ObjRef 类,其中包含生成与实际远程对象通信的代理对象所需的所有信息。在网络上,只传递参数和返回值。远程方法调用要求远程对象在其远程主机(服务器)上调用其方法。

按引用封送类必须继承自 System.MarshalByRefObject

.NET 框架进行的封送处理

封送处理由 .NET Framework 本身完成。我们不必为此编写任何代码。

通道

.NET Remoting 基础设施提供了一种机制,通过该机制可以将字节流从一个点发送到另一个点(客户端到服务器等)。这是通过通道实现的。严格来说,它是一个实现 IChannel 接口的类。System.Runtime.Remoting.Channels 中存在两个预定义的 .NET Remoting 通道:TcpChannelHttpChannel。要使用 TcpChannel,服务器必须实例化并注册 TcpServerChannel 类,客户端必须实例化并注册 TcpClientChannel 类。

通道选择受以下规则约束

  • 在可以调用远程对象之前,必须至少有一个通道注册到 Remoting 框架。通道必须在对象注册之前注册。
  • 通道按应用程序域注册。单个进程中可以有多个应用程序域。当进程死亡时,它注册的所有通道都会自动销毁。
  • 非法多次注册在同一端口上侦听的相同通道。即使通道按应用程序域注册,同一台机器上的不同应用程序域也无法注册在同一端口上侦听的相同通道。您可以为一个应用程序域注册在两个不同端口上侦听的相同通道。
  • 客户端可以使用任何注册的通道与远程对象通信。当客户端尝试连接到远程对象时,Remoting 框架会确保远程对象连接到正确的通道。客户端负责在尝试与远程对象通信之前在 ChannelServices 类上调用 RegisterChannel

序列化格式化程序

.NET Remoting 使用序列化在应用程序域之间复制按值封送的对象,并发送按引用封送的对象的引用。.NET Framework 支持两种序列化:二进制序列化和 XML 序列化。

格式化程序用于在消息通过通道传输之前对其进行编码和解码。.NET 运行时中有两种本机格式化程序,即二进制 (System.Runtime.Serialization.Formatters.Binary) 和 SOAP (System.Runtime.Serialization.Formatters.Soap)。应用程序可以在性能至关重要时使用二进制编码,或者在与其他 Remoting 框架的互操作性至关重要时使用 XML 编码。

一个需要记住的关键点是 .NET Remoting 始终使用二进制序列化,但您可以选择输出格式。序列化类型(二进制或 XML)决定了输出什么对象数据。格式化程序决定了该数据的存储格式。

二进制格式的数据比 XML 格式的数据大小小。较小的尺寸使得二进制格式化成为 Intranet 应用程序或网络性能至关重要时的明显选择。但是,并非所有防火墙都对二进制格式化数据友善,因此如果您正在分发需要通过 Internet 使用 Remoting 的应用程序,您可能会发现自己被迫使用 SOAP 格式化。SOAP 格式化的另一个好处是它具有可读性,这使您有机会检查消息流量进行调试。幸运的是,无论您使用哪种格式化程序,Remoting 的工作方式都完全相同,因此您可以在初始开发和调试期间使用 SOAP 格式化,然后转换为二进制格式进行生产发布。

.NET Remoting 元数据

.NET Remoting 使用元数据动态创建代理对象。在客户端创建的代理对象与原始类具有相同的成员。但代理对象的实现只是通过 .NET Remoting 运行时将所有请求转发到原始对象。序列化格式化程序使用元数据将方法调用转换为有效负载流并转换回来。

客户端可以通过以下方式获取访问远程对象所需的元数据信息

  • 服务器对象的 .NET 程序集。
  • Remoting 对象可以提供一个 WSDL(Web 服务描述语言)文件,描述该对象及其方法。
  • .NET 客户端可以使用 SOAPSUDS 实用程序从服务器(在服务器上生成)下载 XML 模式,以生成仅包含元数据(无代码)的源文件或程序集。

对象激活

对象激活是指实例化远程对象的各种方式。按值封送对象具有简单的激活方案,它们在客户端首次请求时创建。按引用封送对象有两种激活方案

服务器激活对象

服务器激活对象 仅在客户端首次调用远程方法时创建。换句话说,当客户端请求创建远程对象时,只在客户端创建本地代理,服务器上的实际远程对象在第一次方法调用时实例化。这些代理可以生成为

...

// On the Server
RemotingConfiguration.RegisterWellKnownServiceType(
               typeof (RemoteServerObject), "Test",
               WellKnownObjectMode.SingleCall);
...

// On the Client
IRemoteCom obj = (IRemoteCom)Activator.GetObject(typeof(IRemoteCom), 
                  "tcp://:1002/Test");

...

我们有两种注册类型,SingletonSingleCall,前面已经解释过。两者的代码是

RemotingConfiguration.RegisterWellKnownServiceType( typeof(RemoteServerObject), 
          "Test", WellKnownObjectMode.SingleCall);
...

RemotingConfiguration.RegisterWellKnownServiceType( typeof(RemoteServerObject), 
          "Test", WellKnownObjectMode.Singleton);

对于服务器激活对象,代理对象(在客户端)和实际对象(在服务器上)是在不同时间创建的。

客户端激活对象

这些对象在客户端请求时立即在服务器上创建。客户端每次实例化一个客户端激活对象时,无论是通过使用 new 还是 Activator.CreateInstance(...),都会创建一个实例。

...

// On the Server
RemotingConfiguration.ApplicationName = "TestCAO";
RemotingConfiguration.RegisterActivatedServiceType(typeof(RemoteObjectCAO));
...

// On the Client
RemotingConfiguration.RegisterActivatedClientType(typeof(RemoteObjectCAO),
                                          "tcp://:1002/TestCAO");
obj = new RemoteObjectCAO();

...

在所有这些示例中,“localhost”可以替换为实际远程机器的 IP 地址。

何时使用哪种激活取决于不同的场景。其中一些是

  • 单例对象引用同一个服务器对象,一个客户端对该对象所做的任何更改都对所有该对象的客户端可见。可以想象 Windows 桌面,一个程序所做的更改对所有客户端程序都可见。持久数据保存在服务器上,并且所有客户端都可以访问。
  • 使用 SingleCall 模型提供无状态编程模型(传统的 Web 服务请求/响应模型),或者在您不需要在服务器上维护持久对象状态的任何时候。
  • 如果对象需要维护每个客户端的持久状态信息,请使用客户端激活。

对象生命周期和租约

已注册为 SingleCall 的服务器激活对象具有非常简单且有限的生命周期。它只存在一次调用。此后,它被垃圾回收器标记为移除。

另外两种类型,单例和客户端激活对象,它们的生命周期由 .NET Framework 引入的服务(基于租约管理器)管理。在服务器上,应用程序 的租约管理器确定何时应将服务器端对象标记为删除。每个应用程序域都有自己的租约管理器对象。对于具有传输到应用程序外部的对象引用的对象,会创建一个租约。租约具有租约时间;当租约达到零时,它会过期,并且对象会与 .NET Remoting 框架断开连接。一旦 AppDomain 中对对象的所有引用都被释放,当发生下一次垃圾回收时,对象将被回收。发起人是另一个在生命周期中扮演角色的对象。当租约过期时,租约管理器会调用一个或多个租约的发起人,在那里他们有机会续订租约。如果没有发起人决定续订租约,租约管理器会移除租约,并且对象会被垃圾回收。

租约管理器的默认设置是初始生存时间五分钟,每十秒轮询一次,并且每次客户端远程调用都会额外增加两分钟。所有这些值都是可配置的,我们可以覆盖 MarshalByRefObject InitializeLifetimeService() 来在可远程处理对象中定义我们自己的值。

InitializeLifetimeService 方法可以如下覆盖

public override object InitializeLifetimeService()
{
    ILease lease = (ILease)base.InitializeLifetimeService();

    if (lease.CurrentState == LeaseState.Initial)
    {

        // set times very short for demonstration purposes
        lease.InitialLeaseTime = TimeSpan.FromSeconds(25);
        lease.SponsorshipTimeout = TimeSpan.FromSeconds(25);
        lease.RenewOnCallTime = TimeSpan.FromSeconds(20);
    }
    return lease;
}

在此方案下,远程对象(服务器端对象)的生命周期独立于客户端对象的生命周期。服务器和客户端生命周期的解耦是一种非常灵活的设计。考虑一下,实例化成本高的远程对象可以赋予较长的生命周期租约,或者可以由发起人保持活动状态。此外,持有稀缺或重要资源的远程对象可以赋予较短的生命周期,并由垃圾回收器快速回收。更重要的是,这种解耦保证了远程对象将具有有限的生命周期,无论网络条件或任何客户端的存在如何。

续订租约(增加生命周期)

虽然对象有默认的租约期,但有许多方法可以延长租约期以保持对象活动,以防客户端希望在同一个服务器对象中维护状态。

  • 服务器对象可以将其租约时间设置为无限,这指示 Remoting 在垃圾回收周期中不收集它。
  • 客户端可以调用 RemotingServices.GetLifetimeService 方法从 AppDomain 的租约管理器获取服务器对象的租约。从 Lease 对象,客户端可以调用 Lease.Renew 方法来延长租约。
  • 客户端可以在 AppDomain 的租约管理器中注册特定租约的发起人。当远程对象的租约过期时,租约管理器会回调发起人以请求续订租约。
  • 如果设置了 ILease::RenewOnCallTime 属性,那么每次对远程对象的调用都会将租约延长 RenewOnCallTime 属性指定的时间量。

一旦对象被封送,租约就从初始状态变为活动状态,并且任何初始化租约属性的尝试都将被忽略(会抛出异常)。InitializeLifetimeService 在远程对象激活时调用。激活后,租约只能续订。

.NET Remoting 实现提供了两种续订远程对象租约的方式。客户端可以直接调用 ILease.Renew,或者客户端可以联系发起人并要求发起人续订租约。

发起人对象侦听来自主机系统租约管理器的查询,并相应地响应。发起人通过获取租约的引用并调用 ILease.Register 来向租约管理器注册。租约管理器会定期查询发起人,以查看其是否希望续订租约。如果发起人希望续订租约,它会返回一个续订 TimeSpan 值以响应服务器的查询。

发起人优于客户端 ILease.Renew 循环,原因有几个。首先,服务器的租约管理器会跟踪对象的租约何时即将过期,并会根据需要查询发起人,以确保在时间用完之前有机会延长租约。它在带宽和处理时间方面也更高效。通常,当单个远程对象有多个客户端时(如单例的情况),租约管理器查询单个对象进行续订比让每个客户端不断 ping 服务器更高效。对于客户端激活对象也是如此,因为它将网络流量减少到保持对象活动所需的最低限度。

您可以让客户端自己实现 ISponsor 接口,也可以创建一个发起人对象来维护一个或多个远程对象和客户端的租约。在这里,我将指定客户端自己实现 ISponsor 的代码。

在可远程处理的客户端类中实现 ISponsor

class RemoteClient: System.MarshalByRefObject, Isponsor

ISponsor 接口要求您实现一个方法 Renewal。返回值是延长租约的时间量,表示为 TimeSpan。我们的 Renewal 方法将延长租约额外 30 秒。这是代码,您应该将其添加到远程客户端

public TimeSpan Renewal (ILease lease)
{
    return TimeSpan.FromSeconds(30);
}

最后,向服务器的租约管理器注册 RemoteClient 对象。在服务器对象实例创建的地方插入以下代码

// Instantiate the object
RemoteableClass MyRemotObject = new RemoteableClass();
// register as a sponsor
ILease lease = (ILease)RemotingServices.GetLifetimeService(MyRemotObject);
lease.Register(this);

如何实现 Remoting

在下面的讨论中,我们将讨论如何在我们的应用程序中实现 Remoting。讨论中给出的代码只是为了展示代码中需要的内容。您可以从源代码文件中获取完整代码。

创建可远程处理对象

可远程处理对象是继承自 MarshalByRefObject 的对象。

创建一个新的 C# 类库项目。添加一个名为 MyRemotableObject 的类,并放入以下代码。在项目中添加对 System.Runtime.Remoting 的引用,否则将找不到 TcpChannel。编译该类以确保一切正确。

MyRemotableObject.cs
namespace RemotableObjects
{
    public class MyRemotableObject : MarshalByRefObject
    { 
        public MyRemotableObject()
        { 
        }
        public void SetMessage(string message)
        {
            Cache.GetInstance().MessageString = message;
        } 
    }
}

创建服务器以暴露可远程处理对象

我们需要创建一个服务器对象,该对象将作为侦听器来接受远程对象请求。对于本示例,我们将使用 TCP/IP 通道。我们首先创建通道实例,然后将其注册为供客户端在特定端口使用。该服务可以注册为 WellKnownObjectMode.SingleCall,这将为每个客户端创建一个新的对象实例,或者注册为 WellKnownObjectMode.Singleton,这将为所有客户端使用一个对象实例。

如果您计划使用 IIS,则无需创建服务器侦听器。出于显而易见的原因,IIS 仅支持使用 HttpChannel。为您的应用程序创建一个虚拟目录,然后将代码放入 Application_Start 事件中以注册您的服务。

对于我们的示例,如果您没有 IIS,我们将继续创建一个服务器侦听器。由于服务需要绑定到一个可用端口,在我们的示例中,我选择了 8080,我知道这是我的计算机上未使用的端口。您可能需要根据您可用的端口选择不同的端口。要查看计算机上使用的端口列表,请打开命令提示符,并发出命令“netstat --a”。它可能会产生很长的列表,因此请确保命令提示符缓冲区大小设置为允许滚动。编译该类以确保一切正确。

创建一个新的 C# Windows 应用程序项目。添加一个名为 frmRServer 的 Windows 窗体,并粘贴以下代码。在项目中添加对 System.Runtime.Remoting 的引用,否则将找不到 TcpChannel。此外,添加对包含 MyRemotableObject 的项目的引用,否则代码将无法编译,因为它不知道如何找到对 MyRemotableObject 的引用。这里,我只给出部分代码。您可以从源代码文件中获取完整代码。

namespace RemotableObjects
{
    public class frmRServer : System.Windows.Forms.Form, IObserver
    {
        private System.Windows.Forms.TextBox textBox1;
        private MyRemotableObject remotableObject;
        private System.ComponentModel.Container components = null;
        public frmRServer()
        {
            InitializeComponent();
            remotableObject = new MyRemotableObject();
            // using TCP protocol
            TcpChannel channel = new TcpChannel(8080);
            ChannelServices.RegisterChannel(channel);
            RemotingConfiguration.RegisterWellKnownServiceType(
               typeof(MyRemotableObject),"HelloWorld",
               WellKnownObjectMode.Singleton);
            RemotableObjects.Cache.Attach(this);
        }
    }
}

创建客户端以使用可远程处理对象

客户端将非常简单。它将连接到服务器,使用服务器创建对象实例,然后执行 SetString 方法。

创建一个新的 C# Windows 应用程序项目。添加一个名为 frmRCleint 的 Windows 窗体,并粘贴以下代码。添加对包含 SampleObject 的项目的引用,否则代码将无法编译,因为它不知道如何找到对 SampleObject 的引用。编译该类以确保一切正确。这里只给出部分代码以展示概念。您可以从给定源获取完整代码

namespace RemotableObjects
{
    public class frmRCleint : System.Windows.Forms.Form
    {
        private System.Windows.Forms.TextBox textBox1; 
        MyRemotableObject remoteObject;
        private System.ComponentModel.Container components = null;
        public frmRCleint()
        {
            InitializeComponent();
            // using TCP protocol 
            // running both client and server on same machines
            TcpChannel chan = new TcpChannel();
            ChannelServices.RegisterChannel(chan);
            // Create an instance of the remote object
            remoteObject = (MyRemotableObject) Activator.GetObject(
              typeof(MyRemotableObject),"tcp://:8080/HelloWorld");
        }
        private void textBox1_TextChanged(object sender, System.EventArgs e)
        {
            remoteObject.SetMessage(textBox1.Text);
        }
    }
}

运行应用程序

要运行应用程序,请编译可远程处理对象项目对象。编译并运行服务器应用程序。编译并运行客户端应用程序。将出现两个对话框:一个用于 Remoting 服务器,一个用于 Remoting 客户端。Remoting 服务器将侦听请求。Remoting 客户端准备将消息传递给服务器。现在,在客户端对话框中键入任何字符串,客户端将通过 Remoting 将其发送到服务器,服务器将在服务器应用程序的对话框中显示该字符串。这是一个简单易懂的 Remoting 演示。

对象配置

有两种配置远程对象的方法。一种是通过代码,另一种是使用配置文件,服务器和客户端都使用。使用配置文件的优点是每次更改配置时我们都不必重新编译代码,因此我们可以随时更改应用程序的配置,而不会干扰代码或可执行文件。按照约定,配置文件的名称格式为 executablename.config

配置文件

典型的配置文件除其他信息外,还包括以下内容

  • 宿主应用程序信息
  • 对象名称
  • 对象的 URI
  • 正在注册的通道(可以同时注册多个通道)
  • 服务器对象的租约时间信息

这是一个配置文件的示例

服务器远程配置 (server.exe.config)

<configuration>
 <system.runtime.remoting>
  <application name="server">
   <service>
    <activated type="remote.ServiceClass, remote"/>
   </service>
   <channels>
    <channel ref="http" port="8080">
     <serverProviders>
      <formatter ref="binary" typeFilterLevel="Full"/>
     </serverProviders>
     <clientProviders>
      <formatter ref="binary"/>
     </clientProviders>
    </channel>
   </channels>
  </application>
 </system.runtime.remoting>
</configuration>

客户端远程配置 (client.exe.config)

<configuration>
 <system.runtime.remoting>
  <application name="client">
   <client url = "https://:8080">
    <activated type="remote.ServiceClass, remote"/>
   </client>
   <channels>
    <channel ref="http" port="0">
     <serverProviders>
      <formatter ref="binary" typeFilterLevel="Full"/>
     </serverProviders>
     <clientProviders>
      <formatter ref="binary"/>
     </clientProviders>
    </channel>
   </channels>
  </application>
 </system.runtime.remoting>
</configuration>

要在我们的 Remoting 测试应用程序中使用这些配置文件,请将这些文件 (server.configclient.config) 放在包含 server.execlient.exe 程序的目录中。

使用应用程序配置文件极大地简化了设置远程应用程序所需的代码。例如,此处显示的单行代码取代了 server.cs 程序的 Main 方法中的所有配置代码

RemotingConfiguration.Configure("server.config");

所示的配置文件设置了客户端激活——每个客户端都有自己的对象。如果您想配置为单例模式,请更改服务器配置文件的 <service> 部分,使其读取

<service>
   <wellknown
   type="remote.ServiceClass, remote"
   objectUri="ServiceURI"
   mode="Singleton"
/>
</service>

并更改客户端配置文件的 <client> 部分,使其读取

<client url = "https://:8080">
    <wellknown
    type="remote.ServiceClass, remote"
    url="https://:8080/ServiceURI"
/>
</client>

通过代码配置

服务器

TcpServerChannel channel = new TcpServerChannel(rs.mPort);
ChannelServices.RegisterChannel(channel);
RemotingConfiguration.RegisterWellKnownServiceType(
       typeof(RemoteServerObject), "Test",
       WellKnownObjectMode.SingleCall);

客户端

TcpClientChannel chan = new TcpClientChannel();
ChannelServices.RegisterChannel(chan);
IRemoteCom obj = (IRemoteCom)Activator.GetObject(typeof(IRemoteCom), 
                 "tcp://:1002/Test");

托管 .NET Remoting 对象

.NET Remoting 对象可以托管在

  • 托管可执行文件

    NET Remoting 对象可以托管在任何常规 .NET EXE 或托管服务中。

  • IIS

    Remoting 对象可以托管在 Internet Information Server (IIS) 中。默认情况下,托管在 IIS 中的 Remoting 对象通过 HTTP 通道接收消息。要在 IIS 下托管 Remoting 对象,必须创建一个虚拟根目录,并将一个“remoting.config”文件复制到其中。包含远程对象的可执行文件或 DLL 应放置在 IIS 根目录指向的目录下的 bin 目录中。重要的是要注意 IIS 根目录名称应与配置文件中指定的应用程序名称相同。当应用程序收到第一条消息时,Remoting 配置文件会自动加载。

  • .NET 组件服务

    NET Remoting 对象可以托管在 .NET 组件服务基础设施中,以利用各种 COM+ 服务,如事务、JIT 和对象池。

MyRemotableObject remoteObject;
private System.ComponentModel.Container components = null;
public frmRCleint()
{
    InitializeComponent();
    // using TCP protocol 
    // running both client and server on same machines
    TcpChannel chan = new TcpChannel();
    ChannelServices.RegisterChannel(chan);
    // Create an instance of the remote object
    remoteObject = (MyRemotableObject) Activator.GetObject(
                    typeof(MyRemotableObject),"tcp://:8080/HelloWorld");
}
private void textBox1_TextChanged(object sender, System.EventArgs e)
{
    remoteObject.SetMessage(textBox1.Text);
}

运行应用程序

要运行应用程序,请编译可远程对象项目对象。编译并运行服务器应用程序。编译并运行客户端应用程序。将出现两个对话框,一个用于远程处理服务器,一个用于远程处理客户端。远程处理服务器将侦听请求。远程处理客户端已准备好将消息传递给服务器。现在,在客户端对话框中键入任何字符串,客户端将通过远程处理将其发送到服务器,服务器将在服务器应用程序的对话框中显示该字符串。这是一个简单易懂的远程处理的简单演示。

历史

  • 2006 年 7 月 13 日:初始版本

许可证

本文未附加明确的许可证,但可能在文章文本或下载文件本身中包含使用条款。如有疑问,请通过下面的讨论区联系作者。

作者可能使用的许可证列表可以在此处找到。

© . All rights reserved.