分类

链接

2011 年 12 月
 1234
567891011
12131415161718
19202122232425
262728293031  

近期文章

热门标签

新人福利,免费薅羊毛

现在位置:    首页 > .NET > 正文
共享办公室出租
Remoting 生存期租约
.NET 暂无评论 阅读(2,640)

Remoting 采取了一种称之为 "租约" 的机制来管理远程对象(Singleton、CAO)的生存期策略。每个应用程序域中都有一个租约管理器(LifetimeServices),它负责管理所有参与生存期的远程对象租约。租约管理器定期检查所有租约以确定过期的租约时间,如果租约已过期,将向该对象发起人(Sponsor)的发送请求,查询是否有谁要续订租约,若没有任何发起人续订该租约,租约将被移除,该远程对象也会被删除等待垃圾回收器回收。如果远程对象被发起人多次续订租约或被客户端持续调用,其生存期可以比其生存期租约长得多。

所谓发起人 (Sponsor,MSDN 翻译为"主办方",真别扭!) 就是一个或多个与远程对象关联,用于定义租约延长时间的对象。租约管理器通过回调发起人方法(ISponsor.Renewal)来查询是否续订租约。发起人需要继承自 MarshalByRefObject,且必须实现 ISponsor 接口。在 System.Runtime.Remoting.Lifetime 名字空间中,Framework 为我们提供了一个缺省实现 —— ClientSponsor。

租约参数

  • 当参与生存期管理的远程对象被创建后,其租约被设置为 LifetimeServices.LeaseTime 或 ILease.InitialLeaseTime。
  • 我们可以通过 ILease.CurrentLeaseTime 来检查对象租约过期的剩余时间。
  • 客户端调用远程对象方法时,会发生隐式续订租约行为。当 CurrentLeaseTime 小于 RenewOnCallTime,则租约被设置为 RenewOnCallTime。
  • 租约管理器每隔一定时间(LeaseManagerPollTime)检查一次租约列表,如果某租约过期则通知其发起人,询问是否进行续订。如发起人未能在 SponsorshipTimeout 时间内响应,则移除该主办方并调用另一主办方。如果没有其他主办方,则租约过期,且垃圾回收器将处置该远程对象。

租约过期试验

using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Threading;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.CompilerServices;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Lifetime;

namespace Learn.Library.Remoting
{
    public class RemotingTest2
    {
        /// <summary>
        /// 远程类型
        /// </summary>
        public class Data : MarshalByRefObject
        {
            private Guid guid = Guid.NewGuid();

            public void Test()
            {
                Console.WriteLine("{0} in {1}...", guid, AppDomain.CurrentDomain.FriendlyName);
                Console.WriteLine((InitializeLifetimeService() as ILease).CurrentLeaseTime);
            }
        }

        /// <summary>
        /// 服务器端代码
        /// </summary>
        static void Server()
        {
            // 创建新的应用程序域,以便模拟分布结构。
            AppDomain server = AppDomain.CreateDomain("server");
            server.DoCallBack(delegate
            {
                // 设置缺省生存期
                LifetimeServices.LeaseTime = TimeSpan.FromSeconds(1);
                LifetimeServices.RenewOnCallTime = TimeSpan.FromSeconds(1);
                LifetimeServices.LeaseManagerPollTime = TimeSpan.FromSeconds(1);
                LifetimeServices.SponsorshipTimeout = TimeSpan.FromSeconds(1);

                TcpServerChannel channel = new TcpServerChannel(801);
                ChannelServices.RegisterChannel(channel, false);
                RemotingConfiguration.RegisterWellKnownServiceType(typeof(Data), "data",
                    WellKnownObjectMode.Singleton);
            });
        }

        /// <summary>
        /// 客户端代码
        /// </summary>
        static void Client()
        {
            TcpClientChannel channel = new TcpClientChannel();
            ChannelServices.RegisterChannel(channel, false);
            RemotingConfiguration.RegisterWellKnownClientType(typeof(Data), "tcp://localhost:801/data");

            // 创建远程对象并调用其方法
            for (int i = 0; i < 3; i++)
            {
                Data data = new Data();
                data.Test();
                Thread.Sleep(5000);
            }
        }

        static void Main()
        {
            Server();
            Client();
        }
    }
}

输出:
6ac6fcb9-6a5d-427b-92bb-cfdcb2265911 in server...
00:00:00.9899856
86a1716f-1ebd-47d2-af80-e501d20813b9 in server...
00:00:01
9a1039e0-fac7-4bbb-80c4-0bc7d5c9c2ff in server...
00:00:01

通过输出结果,我们发现 Singleton MBR 对象过期后重新创建。

初始化租约

1. 默认租约:用 LifetimeServices 设置所有对象的默认租约。

LifetimeServices.LeaseTime = TimeSpan.FromSeconds(1);
LifetimeServices.RenewOnCallTime = TimeSpan.FromSeconds(1);
LifetimeServices.LeaseManagerPollTime = TimeSpan.FromSeconds(1);
LifetimeServices.SponsorshipTimeout = TimeSpan.FromSeconds(1);

2. 自定义租约:重写 MarshalByRefObject.InitializeLifetimeService() 自定义对象租约。当 ILease.CurrentState 属性为 LeaseState.Initial 时,可以设置租约的属性。一旦设置,就不能直接更改它们。

public class Data : MarshalByRefObject
{
    public override object InitializeLifetimeService()
    {
        ILease lease = (ILease)base.InitializeLifetimeService();
        if (lease.CurrentState == LeaseState.Initial)
        {
            lease.InitialLeaseTime = TimeSpan.FromSeconds(1);
            lease.SponsorshipTimeout = TimeSpan.FromSeconds(1);
            lease.RenewOnCallTime = TimeSpan.FromSeconds(2);
        }

        return lease;
    }
}

续订租约

续订租约的方式有:

  • 隐式续订:在调用远程对象方法时发生。
  • 显示续订:调用 ILease.Renew()。
  • 发起租约:通过创建发起人(Sponsor)来延长租约。

在客户端调用 ILease.Renew() 显示续订租约,如果 CurrentLeaseTime 小于续订时间,则租约时间被设置为续订时间。

static void Client()
{
    // 创建并注册信道
    TcpClientChannel channel = new TcpClientChannel();
    ChannelServices.RegisterChannel(channel, false);

    // 注册远程对象
    RemotingConfiguration.RegisterWellKnownClientType(typeof(Data), "tcp://localhost:801/data");

    // 创建远程对象并调用其方法
    Data data = new Data();
    (data.GetLifetimeService() as ILease).Renew(TimeSpan.FromSeconds(100));
}

============ 欢迎各位老板打赏~ ===========

本文版权归Bruce's Blog所有,转载引用请完整注明以下信息:
本文作者:Bruce
本文地址:Remoting 生存期租约 | Bruce's Blog

发表评论

留言无头像?