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

使用.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 最大值加上 RenewOnCallTimeLeaseTime 即将过期时,发起者会被要求更新租约。因为我们有时会遇上网络不稳定,所以可能会找不到租约发起者。为了确保不在服务器上留下无效对象,每个租约都带有一个 SponsorshipTimeout。该值指定了租约终止之前等待租约发起者回复的时间长度。如果 SponsershipTimeout 为零,CurrentLeaseTime 会被用于确定租约的过期时间。如果 CurrentLeaseTime 的值为零,则租约不会过期。配置或 API 可用于替代 InitialLeaseTimeSponsorshipTimeout RenewOnCallTime 的默认值。

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

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

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

示例代码:

 1None.gif<?xml version="1.0" encoding="utf-8" ?>
 2None.gif<configuration>
 3None.gif    <system.runtime.remoting>
 4None.gif        <application>
 5None.gif            <service>
 6None.gif                <wellknown 
 7None.gif                    mode="Singleton" 
 8None.gif                    type="RemotingSamples.HelloServer, General" 
 9None.gif                    objectUri="SayHello" />
10None.gif            </service>
11None.gif            <channels>
12None.gif                <channel port="8086" ref="http"/>
13None.gif            </channels>
14None.gif            
15None.gif            <lifetime 
16None.gif               leaseTime="7M" 
17None.gif               sponsorshipTimeout="7M" 
18None.gif               renewOnCallTime="7M"
19None.gif               leaseManagerPollTime="7S"
20None.gif               />
21None.gif        </application>
22None.gif    </system.runtime.remoting>
23None.gif</configuration>
24None.gif

三.编写代码配置租约

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

示例代码:

 1None.gif public override Object InitializeLifetimeService()
 2ExpandedBlockStart.gifContractedBlock.gif        dot.gif{
 3InBlock.gif
 4InBlock.gif            ILease lease = (ILease)base.InitializeLifetimeService();
 5InBlock.gif            // Normally, the initial lease time would be much longer.
 6InBlock.gif            // It is shortened here for demonstration purposes.
 7InBlock.gif            if (lease.CurrentState == LeaseState.Initial)
 8ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
 9InBlock.gif                lease.InitialLeaseTime = TimeSpan.FromSeconds(3);
10InBlock.gif                lease.SponsorshipTimeout = TimeSpan.FromSeconds(10);
11InBlock.gif                lease.RenewOnCallTime = TimeSpan.FromSeconds(2);
12ExpandedSubBlockEnd.gif            }

13InBlock.gif            return lease;
14ExpandedBlockEnd.gif        }

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

租约状态的枚举值

说明

Active

指明租约处于激活状态

Expired

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

Initial

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

Null

租约还没有被初始化

Renewing

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

 

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

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

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

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

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

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

示例代码:

 1None.gifusing System;
 2None.gifusing System.Runtime.Remoting;
 3None.gifusing System.Runtime.Remoting.Channels;
 4None.gifusing System.Runtime.Remoting.Channels.Tcp;
 5None.gifusing System.Runtime.Remoting.Channels.Http;
 6None.gifusing System.Runtime.Remoting.Activation;
 7None.gifusing System.Runtime.Remoting.Lifetime;
 8None.gifusing System.IO;
 9None.gif
10None.gifnamespace RemotingSamples 
11ExpandedBlockStart.gifContractedBlock.gifdot.gif{
12InBlock.gif    public class Client
13ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
14InBlock.gif        public static void Main(string[] args)
15ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
16InBlock.gif            //使用TCP通道得到远程对象
17InBlock.gif            ChannelServices.RegisterChannel(new HttpChannel());
18InBlock.gif
19InBlock.gif            HelloServer obj = (HelloServer)Activator.GetObject(
20InBlock.gif              typeof(RemotingSamples.HelloServer),
21InBlock.gif              "http://localhost:8086/SayHello");
22InBlock.gif            if (obj == null)
23ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
24InBlock.gif                System.Console.WriteLine(
25InBlock.gif                    "Could not locate HTTP server");
26ExpandedSubBlockEnd.gif            }

27InBlock.gif            
28InBlock.gif
29InBlock.gif            MySponsor sponsor = new MySponsor();
30InBlock.gif            sponsor.RenewalTime = TimeSpan.FromMinutes(2);
31InBlock.gif            sponsor.Register(obj);
32InBlock.gif
33InBlock.gif            ILease lease = (ILease)obj.GetLifetimeService();
34InBlock.gif            if (lease != null)
35ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
36InBlock.gif                Console.WriteLine("Lease Configuration:");
37InBlock.gif                Console.WriteLine("InitialLeaseTime: " +
38InBlock.gif                    lease.InitialLeaseTime);
39InBlock.gif                Console.WriteLine("RenewOnCallTime: " +
40InBlock.gif                    lease.RenewOnCallTime);
41InBlock.gif                Console.WriteLine("SponsorshipTimeout: " +
42InBlock.gif                    lease.SponsorshipTimeout);
43InBlock.gif                Console.WriteLine(lease.CurrentLeaseTime);
44ExpandedSubBlockEnd.gif            }

45InBlock.gif
46ExpandedSubBlockEnd.gif        }

47InBlock.gif
48ExpandedSubBlockEnd.gif    }

49InBlock.gif
50InBlock.gif    public class MySponsor:ClientSponsor,ISponsor
51ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
52InBlock.gif        TimeSpan ISponsor.Renewal(ILease lease)
53ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
54InBlock.gif            Console.WriteLine("Renewal called");
55InBlock.gif
56InBlock.gif            return this.RenewalTime;
57ExpandedSubBlockEnd.gif        }

58ExpandedSubBlockEnd.gif    }

59ExpandedBlockEnd.gif}

60None.gif


五.总结

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

 

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

 Server.cs

 1None.gifusing System;
 2None.gifusing System.Runtime.Remoting;
 3None.gifusing System.Runtime.Remoting.Channels;
 4None.gifusing System.Runtime.Remoting.Channels.Tcp;
 5None.gifusing System.Runtime.Remoting.Channels.Http;
 6None.gif
 7None.gifnamespace RemotingSamples 
 8ExpandedBlockStart.gifContractedBlock.gifdot.gif{
 9InBlock.gif
10InBlock.gif    public class Server
11ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
12InBlock.gif        public static int Main(string [] args) 
13ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
14InBlock.gif
15InBlock.gif
16InBlock.gif             TcpChannel chan1 = new TcpChannel(8085);
17InBlock.gif            HttpChannel chan2 = new HttpChannel(8086);
18InBlock.gif
19InBlock.gif            ChannelServices.RegisterChannel(chan1);
20InBlock.gif            ChannelServices.RegisterChannel(chan2);
21InBlock.gif
22InBlock.gif            //服务器端激活。
23InBlock.gif            RemotingConfiguration.RegisterWellKnownServiceType
24InBlock.gif                (
25InBlock.gif                typeof(HelloServer),
26InBlock.gif                "SayHello",
27InBlock.gif                WellKnownObjectMode.Singleton
28InBlock.gif                );      
29InBlock.gif
30InBlock.gif            System.Console.WriteLine("Press Enter key to exit");
31InBlock.gif            System.Console.ReadLine();
32InBlock.gif            return 0;
33ExpandedSubBlockEnd.gif        }

34InBlock.gif
35ExpandedSubBlockEnd.gif    }

36ExpandedBlockEnd.gif}

37None.gif


HelloWord.cs

 1None.gifusing System;
 2None.gifusing System.Collections.Generic;
 3None.gifusing System.Text;
 4None.gifusing System.Runtime.Remoting.Lifetime;
 5None.gif
 6None.gifnamespace RemotingSamples
 7ExpandedBlockStart.gifContractedBlock.gifdot.gif{
 8InBlock.gif    public class HelloServer : MarshalByRefObject
 9ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
10InBlock.gif        public HelloServer()
11ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
12InBlock.gif            Console.WriteLine("HelloServer activated");
13ExpandedSubBlockEnd.gif        }

14InBlock.gif        public String HelloMethod(String name)
15ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
16InBlock.gif            Console.WriteLine(
17InBlock.gif                "Server Hello.HelloMethod : {0}", name);
18InBlock.gif            return "Hi there " + name;
19ExpandedSubBlockEnd.gif        }

20InBlock.gif
21InBlock.gif        // Overrides the lease settings for this object.
22InBlock.gif        public override object InitializeLifetimeService()
23ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
24InBlock.gif
25InBlock.gif            ILease lease = (ILease)base.InitializeLifetimeService();
26InBlock.gif            // Normally, the initial lease time would be much longer.
27InBlock.gif            // It is shortened here for demonstration purposes.
28InBlock.gif            if (lease.CurrentState == LeaseState.Initial)
29ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
30InBlock.gif                lease.InitialLeaseTime = TimeSpan.FromSeconds(3);
31InBlock.gif                lease.SponsorshipTimeout = TimeSpan.FromSeconds(10);
32InBlock.gif                lease.RenewOnCallTime = TimeSpan.FromSeconds(2);
33ExpandedSubBlockEnd.gif            }

34InBlock.gif            return lease;
35ExpandedSubBlockEnd.gif        }

36InBlock.gif
37ExpandedSubBlockEnd.gif    }

38ExpandedBlockEnd.gif}

39None.gif
40None.gif        
41None.gif
42None.gif
43None.gif


Client.cs
 

 1None.gifusing System;
 2None.gifusing System.Runtime.Remoting;
 3None.gifusing System.Runtime.Remoting.Channels;
 4None.gifusing System.Runtime.Remoting.Channels.Tcp;
 5None.gifusing System.Runtime.Remoting.Channels.Http;
 6None.gifusing System.Runtime.Remoting.Activation;
 7None.gifusing System.Runtime.Remoting.Lifetime;
 8None.gifusing System.IO;
 9None.gif
10None.gifnamespace RemotingSamples 
11ExpandedBlockStart.gifContractedBlock.gifdot.gif{
12InBlock.gif    public class Client
13ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
14InBlock.gif        public static void Main(string[] args)
15ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
16InBlock.gif            //使用TCP通道得到远程对象
17InBlock.gif            ChannelServices.RegisterChannel(new HttpChannel());
18InBlock.gif
19InBlock.gif            HelloServer obj = (HelloServer)Activator.GetObject(
20InBlock.gif              typeof(RemotingSamples.HelloServer),
21InBlock.gif              "http://localhost:8086/SayHello");
22InBlock.gif            if (obj == null)
23ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
24InBlock.gif                System.Console.WriteLine(
25InBlock.gif                    "Could not locate HTTP server");
26ExpandedSubBlockEnd.gif            }
27InBlock.gif            
28InBlock.gif
29InBlock.gif            ILease lease = (ILease)obj.GetLifetimeService();
30InBlock.gif            if (lease != null)
31ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
32InBlock.gif                Console.WriteLine("Lease Configuration:");
33InBlock.gif                Console.WriteLine("InitialLeaseTime: " +
34InBlock.gif                    lease.InitialLeaseTime);
35InBlock.gif                Console.WriteLine("RenewOnCallTime: " +
36InBlock.gif                    lease.RenewOnCallTime);
37InBlock.gif                Console.WriteLine("SponsorshipTimeout: " +
38InBlock.gif                    lease.SponsorshipTimeout);
39InBlock.gif                Console.WriteLine(lease.CurrentLeaseTime);
40ExpandedSubBlockEnd.gif            }

41InBlock.gif
42ExpandedSubBlockEnd.gif        }

43InBlock.gif
44ExpandedSubBlockEnd.gif    }

45InBlock.gif
46ExpandedBlockEnd.gif}

47None.gif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/408198.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

配置 Sybase数据源

1.Start-- > All Programs -- > Sybase - -> Connectivity --> click ‘Open Client Directory Service Editor’ 2.在Server窗口右击鼠标 Right Click -- > select ‘Add’ item 3 弹出’Input Server Name’窗口,输入Server name(服务器名称) ServerName: DM…

C++虚函数表

虚函数 对C 了解的人都应该知道虚函数&#xff08;Virtual Function&#xff09;是通过一张虚函数表&#xff08;Virtual Table&#xff09;来实现的。简称为V-Table。在这个表中&#xff0c;主是要一个类的虚函数的地址表&#xff0c;这张表解决了继承、覆盖的问题&#xff0…

Proxy Pattern using C# (转载)

Proxy Pattern&#xff08;代理模式&#xff09;属于Structural Pattern&#xff08;结构型模式&#xff09;&#xff0c;Proxy Pattern-为Client真正要调用的对象提供一个代理&#xff08;Surrogate or placeholder&#xff09;&#xff0c;来控制Client对该对象的访问。 1. U…

BlackBerry 应用程序开发者指南 第一卷:基础--第5章 支持的媒体内容(Media Content)...

作者:Confach 发表于April 23,2006 15:02 pm版权信息:可以任意转载, 转载时请务必以超链接形式标明文章原始出处 和作者信息.http://www.cnblogs.com/confach/articles/387902.html5第5章 支持的媒体内容&#xff08;Media Content&#xff09;PME内容 播放媒体内容 监听媒体内…

Qt 入门 ---- 如何在程序窗口显示图片?

步骤&#xff1a; 1. 选择资源&#xff08;准备图片&#xff09; 2. 加载资源&#xff08;导入图片&#xff09; 3. 使用资源&#xff08;显示图片&#xff09; 具体操作流程&#xff1a; ① 从网上寻找合适的图片素材&#xff0c;下载到本地&#xff0c;在项目根目录下创建一个…

Enterprise Library 2.0 技巧(3):记录ASP.NET站点中未处理的异常

这篇文章不能算是Enterprise Library 2.0的一个技巧&#xff0c;只是Logging Application Block的一个简单应用而已&#xff0c;在这里我们使用Logging Application Block来记录一个ASP.NET 2.0站点中未处理的异常到数据库中&#xff0c;当然你也可以记录到文本文件中&#xff…

C++自定义对象如何支持Range-based循环语法

自定义对象如何支持Range-based循环语法 至少实现以下两种语法: //返回第一个迭代子的位置 Iterator begin() //返回最后一个迭代子的下一个位置 Iterator end()迭代子需要支持如下三种方法: operator(自增)operator! (判不等)operator* (解引用) #include <iostream>…

SharePoint 2013 本地开发解决方案以及程调试

SharePoint 2013 本地开发解决方案以及程调试 在SharePoint开发中&#xff0c;我们需要在部署有SharePoint环境的服务器中开发&#xff0c;这是一件让人很苦恼的事情&#xff0c;毕竟不能一个项目多人开发配备多台服务器&#xff0c;这就需要本地开发。 本来自己以为SharePoint…

Linux与C++11多线程编程(学习笔记)

多线程编程与资源同步 在Windows下,主线程退出后,子线程也会被关闭; 在Linux下,主线程退出后,系统不会关闭子线程,这样就产生了僵尸进程 3.2.1创建线程 Linux 线程的创建 #include <unistd.h> #include <stdio.h> #include <pthread.h> void* threadfunc(…

TCP网络编程的基本流程

TCP网络编程的基本流程 对于服务端,通常为以下流程: 调用socket函数创建socket调用bind函数将socket绑定到某个IP和端口上调用listen开始监听当有客户端请求连接上来时,调用accept函数接受连接,产生一个新的socket基于新产生的socket调用send或recv函数,开始与客户端进行数据…