使用.NET Remoting开发分布式应用——基于租约的生存期

一.概述

知名类型的SingleCall对象可以在客户程序的方法调用之后被垃圾收集器清理掉,因为它没有保持状态,属于无状态的。而客户激活的类型的对象和知名类型的SingleTon对象都属于生存期长的对象,如果在客户程序停止使用远程对象之前,远程对象被禁用了,则客户程序会得到一个RemotingException异常。因为该对象已经和下一个方法调用(从客户程序进行的方法调用)断开了连接,只要客户程序需要该对象,它就必须被激活。

微软的DCOM技术使用了Ping机制,在这种机制下,客户程序有规律的对服务程序发出Ping请求,以通知服务程序自己仍旧活着,并通知服务程序自己需要使用哪个对象。.NET Remoting使用的是基于租约的生存期机制,在租约期内,对象一直存活着,直到租借时间结束,.NET Remoting使用Leasing程序完成了这项工作。

.NET Remoting允许我们通过一些方式来修改对象的租约时间,一种方式是编写程序代码来完成,另外一种方式是使用配置文件(有关配置文件的介绍可以参见《使用.NET Remoting开发分布式应用——配置文件篇》的内容),还有一种方式是通过发起人(Sponsor)来配置租约。先来看一下租约配置选项的默认值:


租约配置


默认值(秒)


LeaseTime


300


RenewOnCallTime


120


SponsorshipTimeout


120


LeaseManagerPollTime


10

使用LeaseTime选项可以定义远程对象的最长租借时间。如果客户程序一段时期内不再需要远程对象了,那么该对象将被禁用。每次客户程序使用远程对象调用方法时,RenewOnCallTime定义的一个值会递增租借时间。SponsorshipTimeout选项定义了在调用结束之前的那段默认时间,而LeaseManagerPollTime定义了发起人必须返回延长的那部分租借时间。

租约可以实现 ILease 接口并存储一个属性集合,用于确定更新的策略和方法。您也可以使用调用来更新租约。每次调用远程对象上的方法时,租约时间都会设置为目前 LeaseTime 最大值加上 RenewOnCallTime。LeaseTime 即将过期时,发起者会被要求更新租约。因为我们有时会遇上网络不稳定,所以可能会找不到租约发起者。为了确保不在服务器上留下无效对象,每个租约都带有一个 SponsorshipTimeout。该值指定了租约终止之前等待租约发起者回复的时间长度。如果 SponsershipTimeout 为零,CurrentLeaseTime 会被用于确定租约的过期时间。如果 CurrentLeaseTime 的值为零,则租约不会过期。配置或 API 可用于替代 InitialLeaseTime、SponsorshipTimeout 和 RenewOnCallTime 的默认值。

租约管理器维护着一个按发起时间从大到小存储的发起者列表(它们实现 ISponsor 接口)。需要调用发起者以更新租约时间时,租约管理器会从列表的顶部开始向一个或多个发起者要求更新租约时间。列表顶部的发起者表示其以前请求的租约更新时间最长。如果发起者没有在 SponsorshipTimeOut 时间段内响应,则它会被从列表中删除。通过调用 GetLifetimeService 并将对象租约作为参数,即可以获得该对象租约。该调用是 RemotingServices 类的一个静态方法。如果对象在应用程序域内部,则该调用的参数是对象的本地引用,且返回的租约也是该租约的本地引用。如果对象是远程的,则代理会作为一个参数传递,且返回给调用方的是租约的透明代理。

二.通过配置文件配置租约

在服务器上的应用程序配置文件中编写生存期的配置。在这种方式下,生存期配置对整个应用程序都有效。在应用程序配置文件的<lifttime>标记中,可以通过修改特性的方式来配置。

示例代码:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.runtime.remoting>
        <application>
            <service>
                <wellknown
                    mode="Singleton"
                    type="RemotingSamples.HelloServer, General"
                    objectUri="SayHello" />
            </service>
            <channels>
                <channel port="8086" ref="http"/>
            </channels>

            <lifetime
               leaseTime="7M"
               sponsorshipTimeout="7M"
               renewOnCallTime="7M"
               leaseManagerPollTime="7S"
               />
        </application>
    </system.runtime.remoting>
</configuration>

三.编写代码配置租约

如果我们需要一些带有不同的生存期要求的远程对象,那么最好是通过编程的方式来为对象设置生存期。在远程对象中,可以覆盖InitializeLifetimeService()方法。基类MarshalByRefObject中的InitializeLifetimeService()方法会返回一个对Ilease接口(该接口可用于修改默认值)的引用,因为只有在租约没有生效的时候才可能修改默认值,所以,我们需要检查租约的当前状态,并把它和枚举值LeaseState.Initial进行比较。

示例代码:

     public override Object InitializeLifetimeService()
        {

            ILease lease = (ILease)base.InitializeLifetimeService();
            // Normally, the initial lease time would be much longer.
            // It is shortened here for demonstration purposes.
            if (lease.CurrentState == LeaseState.Initial)
            {
                lease.InitialLeaseTime = TimeSpan.FromSeconds(3);
                lease.SponsorshipTimeout = TimeSpan.FromSeconds(10);
                lease.RenewOnCallTime = TimeSpan.FromSeconds(2);
            }
            return lease;
        }

租约的状态LeaseState枚举值如下表所示:


租约状态的枚举值


说明


Active


指明租约处于激活状态


Expired


表明租约已经期满,不能再恢复。当租约管理器发现对象上的租约已经期满,它将联系处于发起人列表中的租约发起人,决定是否恢复它的租约。如果发起人的响应超时,它将尝试联系发起人列表中的下一个发起人。如果租约管理器不能成功的从任何一个发起人那里获得一个租约恢复响应,它将租约对象设置为Expired状态。一旦如此,租约对象就不能再复活,只能被垃圾收集器收集


Initial


表明租约还没有被创建,但仍然没有被激活


Null


租约还没有被初始化


Renewing


表明租约已经期满,租约管理器正在寻找发起人。这个状态指出租约管理器正在尝试联系已经为这个对象的租约恢复而注册的租约发起人

只有当租约处于初始状态时,才可以更改租约属性。InitializeLifetimeService 的实现通常调用基类的相应方法,来检索远程对象的现有租约。如果在此之前从未对该对象封送过,则返回的租约会处于其初始状态且可以设置租约属性。一旦封送了对象,则租约会从初始状态变为激活状态,并忽略任何初始化租约属性的尝试(但有一种情况例外)。激活远程对象时将调用 InitializeLifetimeService。通过激活调用可以提供一个租约发起者的列表,而且当租约处于激活状态时,可以随时将其他发起者添加到列表中。

可以下列方式延长租约时间:

  • 客户端可以调用 Lease 类上的 Renew 方法。
  • 租约可以向某个发起者请求 Renewal。
  • 当客户端调用对象上的某个方法时,RenewOnCall 值会自动更新租约。

一旦租约过期,其内部状态会由 Active 变为 Expired,且不再对发起者进行任何调用,对象也会被作为垃圾回收。一般情况下,如果发起者分散在 Web 上或位于某个防火墙的后面,远程对象回叫发起者时会遇到困难。因此,发起者不必与客户端处于同一位置,只要远程对象能够访问得到,它可以为网络上的任意位置。

四.通过发起者来配置租约

我们也可以通过发起者来修改生存期服务数值。通过发起者配置,.NET Remoting运行时使用ISponsor接口来延长远程对象的生存期,ISponsor定义了Renewal()方法,.NET Remoting的基础结构会调用该方法来延长当前对象的租借时间。使用租约参数,可以读取当前租约的配置和租借时间的实际情况。我们必须使用返回值为对象定义额外的租借时间。在下面的示例代码中,创建了一个发起者,并修改它的相关的配置参数。

示例代码:

using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Remoting.Channels.Http;
using System.Runtime.Remoting.Activation;
using System.Runtime.Remoting.Lifetime;
using System.IO;

namespace RemotingSamples
{
    public class Client
    {
        public static void Main(string[] args)
        {
            //使用TCP通道得到远程对象
            ChannelServices.RegisterChannel(new HttpChannel());

            HelloServer obj = (HelloServer)Activator.GetObject(
              typeof(RemotingSamples.HelloServer),
              "http://localhost:8086/SayHello");
            if (obj == null)
            {
                System.Console.WriteLine(
                    "Could not locate HTTP server");
            }

            MySponsor sponsor = new MySponsor();
            sponsor.RenewalTime = TimeSpan.FromMinutes(2);
            sponsor.Register(obj);

            ILease lease = (ILease)obj.GetLifetimeService();
            if (lease != null)
            {
                Console.WriteLine("Lease Configuration:");
                Console.WriteLine("InitialLeaseTime: " +
                    lease.InitialLeaseTime);
                Console.WriteLine("RenewOnCallTime: " +
                    lease.RenewOnCallTime);
                Console.WriteLine("SponsorshipTimeout: " +
                    lease.SponsorshipTimeout);
                Console.WriteLine(lease.CurrentLeaseTime);
            }

        }

    }

    public class MySponsor:ClientSponsor,ISponsor
    {
        TimeSpan ISponsor.Renewal(ILease lease)
        {
            Console.WriteLine("Renewal called");

            return this.RenewalTime;
        }
    }
}


五.总结

通过租约来管理远程对象的生存期可以作为引用计数的一种替代方法,因为当网络连接的性能不可靠时,引用计数会显得复杂和低效。尽管有人会坚持认为远程对象的生存期比所需的时间要长,但与引用计数和连接客户相比,租约降低了网络的繁忙程度,将会成为一种非常受欢迎的解决方案。

附录:一个完整的用程序代码配置租约生存期的例子

Server.cs

using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Remoting.Channels.Http;

namespace RemotingSamples
{

    public class Server
    {
        public static int Main(string [] args)
        {

             TcpChannel chan1 = new TcpChannel(8085);
            HttpChannel chan2 = new HttpChannel(8086);

            ChannelServices.RegisterChannel(chan1);
            ChannelServices.RegisterChannel(chan2);

            //服务器端激活。
            RemotingConfiguration.RegisterWellKnownServiceType
                (
             &bbsp;  typeof(HelloServer),
                "SayHello",
                WellKnownObjectMode.Singleton
                );      

            System.Console.WriteLine("Press Enter key to exit");
            System.Console.ReadLine();
            return 0;
        }

    }
}

HelloWord.cs

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Remoting.Lifetime;

namespace RemotingSamples
{
    public class HelloServer : MarshalByRefObject
    {
        public HelloServer()
        {
            Console.WriteLine("HelloServer activated");
        }
        public String HelloMethod(String name)
        {
            Console.WriteLine(
                "Server Hello.HelloMethod : {0}", name);
            return "Hi there " + name;
        }

        // Overrides the lease settings for this object.
        public override object InitializeLifetimeService()
        {

            ILease lease = (ILease)base.InitializeLifetimeService();
            // Normally, the initial lease time would be much longer.
            // It is shortened here for demonstration purposes.
            if (lease.CurrentState == LeaseState.Initial)
            {
                lease.InitialLeaseTime = TimeSpan.FromSeconds(3);
                lease.SponsorshipTimeout = TimeSpan.FromSeconds(10);
                lease.RenewOnCallTime = TimeSpan.FromSeconds(2);
            }
            return lease;
        }

    }
}

Client.cs

using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Remoting.Channels.Http;
using System.Runtime.Remoting.Activation;
using System.Runtime.Remoting.Lifetime;
using System.IO;

namespace RemotingSamples
{
    public class Client
    {
        public static void Main(string[] args)
        {
            //使用TCP通道得到远程对象
            ChannelServices.RegisterChannel(new HttpChannel());

            HelloServer obj = (HelloServer)Activator.GetObject(
              typeof(RemotingSamples.HelloServer),
              "http://localhost:8086/SayHello");
            if (obj == null)
            {
                System.Console.WriteLine(
                    "Could not locate HTTP server");
            }

            ILease lease = (ILease)obj.GetLifetimeService();
            if (lease != null)
            {
                Console.WriteLine("Lease Configuration:");
                Console.WriteLine("InitialLeaseTime: " +
                    lease.InitialLeaseTime);
                Console.WriteLine("RenewOnCallTime: " +
                    lease.RenewOnCallTime);
                Console.WriteLine("SponsorshipTimeout: " +
                    lease.SponsorshipTimeout);
                Console.WriteLine(lease.CurrentLeaseTime);
            }

        }

    }

}

出处:http://www.cnblogs.com/Terrylee/archive/2005/11/28/285809.html

时间: 2024-10-13 23:28:20

使用.NET Remoting开发分布式应用——基于租约的生存期的相关文章

使用.NET Remoting开发分布式应用——配置文件篇

我们已经知道可以通过编码的方式配置服务器通道和远程客户机,除此之外,还可以使用配置文件对服务器通道和远程客户机进行配置.使用远程客户机和服务器对象的配置文件的优点在于,用户无需修改任何一行代码,也无需进行重新编译,便可以配置通道和远程对象. .NET提供了Remoting配置文件的标准,基于XML格式. 一.配置文件 1.服务器配置文件: 先来看一个服务器配置文件的实例,然后我再具体解释一下其中的内容: <?xml version="1.0" encoding="utf

初识用.NET Remoting来开发分布式应用

一..NET Remoting简介: .NET Remoting从某种意义上讲是DCOM的替代品.ASP.NET Web服务十分有用,但是这项技术在企业内联网的解决方案中,对于某些业务请求来说并不快,也没有足够的灵活性,而且,ASP.NET Web服务需要有运行时的支持.使用.NET Remoting技术后,可以将Web服务提供给世界上的任何地方.而且可以在所有的应用程序类型中运行Web服务. 二..NET Remoting 的基本原理: 体系结构图如下: 三.几个重要的概念: 1.远程对象:

跟我一起学WCF(2)——利用.NET Remoting技术开发分布式应用

一.引言 上一篇博文分享了消息队列(MSMQ)技术来实现分布式应用,在这篇博文继续分享下.NET平台下另一种分布式技术——.NET Remoting. 二..NET Remoting 介绍 2.1 .NET Remoting简介 .NET REmoting与MSMQ不同,它不支持离线可得,另外只适合.NET平台的程序进行通信.它提供了一种允许对象通过应用程序域与另一个对象进行交互的框架..NET 应用程序都在一个主应用程序域中执行的,在一个应用程序域中的代码不能访问另一个应用程序域的数据,然而在

跟我一起学WCF(3)——利用Web Services开发分布式应用

一.引言 在前面文章中分别介绍了MSMQ和.NET Remoting技术,今天继续分享.NET 平台下另一种分布式技术——Web Services 二.Web Services 详细介绍 2.1 Web Services 概述 Web Services是支持客户端与服务器通过网络互操作的一种软件系统,是一组可以通过网络调用的应用程序API.在Web Services中主要到SOAP/UDDI/WSDL这三个核心概念,下面分别介绍下这三个概念的定义. SOAP:SOAP(Simple Object

利用Web Services开发分布式应用

一.引言 在前面文章中分别介绍了MSMQ和.NET Remoting技术,今天继续分享.NET 平台下另一种分布式技术——Web Services 二.Web Services 详细介绍 2.1 Web Services 概述 Web Services是支持客户端与服务器通过网络互操作的一种软件系统,是一组可以通过网络调用的应用程序API.在Web Services中主要到SOAP/UDDI/WSDL这三个核心概念,下面分别介绍下这三个概念的定义. SOAP:SOAP(Simple Object

开发环境——基于RHEL 6.8开发环境的搭建

开发环境--基于RHEL 6.8开发环境的搭建 本文讲述了基于RHEL 6.8操作系统搭建开发环境,主要安装了GCC 4.9.3.Qt 5.7.Apache 2.4.25.MySQL 5.6.35.本文同时适用于在Linux主机无互联网环境下搭建开发环境,只需要将所需安装包下载后拷贝到Linux主机即可. 一.RHEL6.8安装 1.RHEL 6.8下载 下载RHEL 6.8安装包:rhel-server-6.8-x86_64-dvd.iso 2.RHEL 6.8安装 安装过程中选择Develo

Go 语言开发的基于 Linux 虚拟服务器的负载平衡平台 Seesaw

负载均衡系统 Seesaw Seesaw是由我们网络可靠性工程师用 Go 语言开发的基于 Linux 虚拟服务器的负载平衡平台,就像所有好的项目一样,这个项目也是为了解决实际问题而产生的. Seesaw发布的博客中这样写道:“我们需要能够处理单播(unicast)和任播(anycast)虚拟 IP (VIPs) 流量,使用 NAT 和 DSR (也被称为 DR) 执行负载均衡,执行针对后端的健康检查.特别是,我们需要一个容易管理的平台,可以自动部署配置的变化.在评估了一些包括现有的开源项目的平台

开发《基于Arcgis Online的家政管理服务信息系统》随笔2

解决了三天的一个问题终于搞定了,和大家分享一下... 1.来点开胃菜,  在Sql server 2008中想要增加修改字段,有时不能修改,作如下操作即可搞定此问题, 启动MSSQL SERVER 2008,选择菜单 工具-〉选项-〉左侧有个 设计  器-〉表设计器和数据库设计器.然后去掉“ 阻止保存要求重新创建表的更改”前面的勾.重新启动MSSQL SERVER 2008即可. 2.在flex的Datagrid中加入图片或者其它组件,想要通过Id访问itemRenderer中的组件是不可能的,

Java EE实用开发指南基于Weblogic+EJB3+Struts2+Hibernate+Spring 目录

http://www.cnblogs.com/lauleoi/p/3864254.html http://www.cnblogs.com/lauleoi/p/3864265.html http://www.cnblogs.com/lauleoi/p/3864267.html http://www.cnblogs.com/lauleoi/p/3864268.html http://www.cnblogs.com/lauleoi/p/3864270.html http://www.cnblogs.c