- PR -

スポンサーの実装(.NET リモーティング)

1
投稿者投稿内容
セリカ
会議室デビュー日: 2006/12/18
投稿数: 12
投稿日時: 2007-01-23 23:01
.NETリモーティングで、CAOのスポンサーを実装しています。
市販の参考書で、クライアント側にスポンサーを実装することは成功しました。
ただ、この方法ですと、クライアント側のポート番号を「0(システムが自動で決定する)」としなければなりませんし、ファイアーウォールも通過はできません。

クライアント側でスポンサーを実装せずに、サーバ側でスポンサーを実装することは可能なのでしょうか?
自分なりに試してみたんですが、これだとリース延長ができません。

<サーバ側のコード>
コード:
〜省略〜
myLease = (ILease)base.InitializeLifetimeService();
sponsor = new OcRemotingObjectSponsor();
sponsor.isLease = true;
myLease.Register(sponsor);
myLease.Renew(TimeSpan.FromSeconds(2));
〜省略〜



<リモートオブジェクト>
コード:
class OcRemotingObjectSponsor : MarshalByRefObject, ISponsor
{
    public Boolean isLease = false;
    public TimeSpan Renewal(ILease lease)
    {
        if (isLease)
        {
            // リース延長
            Console.WriteLine("リース更新:" + DateTime.Now.ToLongTimeString());
            return TimeSpan.FromSeconds(60);
        }
        else
        {
            // リース停止
            Console.WriteLine("リース更新:" + DateTime.Now.ToLongTimeString());
            return TimeSpan.Zero;
        }
    }
}



クライアント側でスポンサーを実装して成功したものを、
そのままサーバ側に移し変えたものなのですが・・・

そもそもサーバ側では、スポンサーの実装は無理なのでしょうか?
自動的にリース期間を延長する方法を探しているのですが、何かいい方法をご存知の方がいらっしゃいましたら、ご教授願います。
(リースの管理でファイアーウォールを越すような処理は出来る限りしたくないので、
サーバ側でリース管理できる方法を探しています。)

よろしくお願いいたします。
masa
大ベテラン
会議室デビュー日: 2004/10/28
投稿数: 161
投稿日時: 2007-01-24 23:26
私は逆にCAOを使いませんので「同じように」かどうかは判断できませんが、
リモートオブジェクトの InitializeLifetimeService メソッドをオーバーライドしています。

このメソッドでそのインスタンスに対するリースオブジェクトを作成し、
スポンサーを設定して返すことにより、リースの延長が可能です。
また、null を返すようにすると無制限になります。
但し、WellKnownObjectMode が Singleton でないと状態を保持しておくことはできません。SingleCall は呼び出したメソッドが完了したら終わりですから。

そのオブジェクトが Singleton では都合が悪い場合はリモートオブジェクトは SingleCall としておいて、
リモートオブジェクトのメソッドから、別途状態を管理する静的インスタンスにアクセスするのがよいと思います。

MSDNで MarshalByRefObject クラスの InitializeLifetimeService メソッドを参照してみてください。何分延長するといったサンプルがあるはずです。


[ メッセージ編集済み 編集者: masa 編集日時 2007-01-24 23:35 ]
masa
大ベテラン
会議室デビュー日: 2004/10/28
投稿数: 161
投稿日時: 2007-01-25 00:30
ところで、SAO に切り替えたと決め付けて考えてしまっていましたが、
CAO のままでサーバー側でリース延長できないかということでしょうか。

CAO でも InitializeLifetimeService メソッドのオーバーライドが有効かどうか、
ポートがゼロであることが必要かどうかなどはわかりません。
CAO はまだ試したことがないので結果を教えていただけるとこちらも助かります。
masa
大ベテラン
会議室デビュー日: 2004/10/28
投稿数: 161
投稿日時: 2007-01-25 00:38
CAO でのスポンサー設定に成功したとありますね。
同じところでの悩みかどうかは確認してみてください。

http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=24596&forum=7

TypeFilterLevel を Full にするとのことです。
私は SAO でサーバーからのイベントをクライアントで受け取る仕組みを作成しているのですが、このときにも TypeFilterLevel を Full にする必要がありました。
セリカ
会議室デビュー日: 2006/12/18
投稿数: 12
投稿日時: 2007-01-25 09:50
masaさん、ご回答ありがとうございます。

引用:

MSDNで MarshalByRefObject クラスの InitializeLifetimeService メソッドを参照してみてください。何分延長するといったサンプルがあるはずです。



このページを発見して試してはいるのですが、このメソッドですと、
初期リースは延長できるのですが、それ以降を自動的に延長してくれないようです。
例えば、クライアントのプログラムをサーバアクセスせずに、数分(設定値)放置して、
サーバアクセスすると既にリモートオブジェクトとの関係は切れています。

引用:

CAO でのスポンサー設定に成功したとありますね。
同じところでの悩みかどうかは確認してみてください。

http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=24596&forum=7



この過去ログの内容は、”クライアント側”でのスポンサーの実装だと思います。
(この過去ログの人と同じ本を読んでいるので・・・^^;)

マイクロソフトのホームページを見ていると、サーバ側でのリース管理が
可能みたいなことを読んだ記憶があるのですが。。。
技術書にも、ファイアーウォール内でのリース管理が不可欠と書いてますし。

やはり常識的に考えて、サーバ側からみてクライアントが生き続けている限り、
リースを自動的に延長するというのは、クライアント側とサーバ側で何らかの
通信をしないといけないということですよね。。。
ってことは、サーバ側でリースの自動延長なんてのは、そもそも無理なのでしょうか・・・

引き続き、情報を持ってらっしゃる方がいらしたら、情報&ご意見お待ちしております。


[ メッセージ編集済み 編集者: セリカ 編集日時 2007-01-25 09:53 ]
masa
大ベテラン
会議室デビュー日: 2004/10/28
投稿数: 161
投稿日時: 2007-01-25 16:45
求めているものが

・クライアントポートを明示的に割り当てる
・ステートフルなリモートオブジェクトを作る
・リース期間を延長したい
・リースの停止はクライアントから指示したい

であれば、"ファクトリー" でオブジェクトを作成させるという手があります。
作成したオブジェクト自体のリモート定義は行っていません。
単なる MarshalByRefObject ということになるでしょうか。

以前にネットから取得したサンプルに手を加えてみました。
ちょっと長くて申し訳ないですが、文章で表しにくいのでコードの抜粋をコピーします。

同一PCでファイアウォールもない環境ですが、
繰り返しリースが延長され、ステートフルなオブジェクトを維持しておくことができました。


// ----- クライアントサイド --------------------

HttpChannel channel = new HttpChannel(8081);
ChannelServices.RegisterChannel(channel);

// ファクトリーを生成(SAOシングルトンオブジェクト)
IRemoteFactory fact = (IRemoteFactory)Activator.GetObject(
    typeof(IRemoteFactory),
    "http://localhost:8080/factory.soap"
  );

// ファクトリーからリモートオブジェクトを取得(単なるMarshaiByRefObject?)
IRemoteObject obj = fact.getNewInstance();

// 400秒間隔でリモートオブジェクトにアクセス
for ( int i = 0; i < 3; i++ ) {

  // 現在の値を取得して 1 を加算
// ステートフルなのであれば加算されていき、ステートレスであれば常に同値
  int nextValue = obj.getValue() + 1;

  // 値を設定
  Console.WriteLine("Client.Main() : Setting value " + nextValue);
  try {
    obj.setValue(nextValue);
  } catch (Exception e) {
    Console.WriteLine("Client.Main(). EXCEPTION \\n{0}",e.Message);
    break;
  }

  Console.WriteLine("Client.Main(): Sleeping 400 second");
  System.Threading.Thread.Sleep(400000);

}

// リース終了(スポンサーを無効にする)
Console.WriteLine("Client.Main() : EndLease");
try {
  obj.EndLease();
} catch {
  Console.WriteLine("Client.Main(). EXCEPTION \\n{0}",e.Message);
}

// しばらく待機して再びアクセスしてみる
Console.WriteLine("Client.Main(): Sleeping 600 second");
System.Threading.Thread.Sleep(600000);

// 値を取得
Console.WriteLine("Client.Main() : Get value ");
try {
  Console.WriteLine("Client.Main() : Get value " + obj.getValue());
} catch (Exception e) {
  Console.WriteLine("Client.Main(). EXCEPTION \\n{0}",e.Message);
}



// ----- インターフェース --------------------

// リモートオブジェクト
public interface IRemoteObject {
  void setValue(int newval);
  int getValue();
  void EndLease();
}

// ファクトリー
public interface IRemoteFactory {
  IRemoteObject getNewInstance();
  IRemoteObject getNewInstance(int initvalue);
}



// ----- サーバーサイド --------------------

// スポンサー
internal class MySponsor : MarshalByRefObject, ISponsor {
  
  public MySponsor() {
    m_CanRenewal = true;
  }

  // 延長可能かどうか
  public bool CanRenewal {
    get { return m_CanRenewal; }
    set { m_CanRenewal = value; }
  }
  private bool m_CanRenewal;

  public TimeSpan Renewal(ILease lease) {
    if ( m_CanRenewal ) {
      Console.WriteLine("MySponsor.Renewal() -- extend 1 min.");
      return new TimeSpan(0, 1, 0);
    } else {
      Console.WriteLine("MySponsor.Renewal() -- end lease ");
      return TimeSpan.Zero;
    }
  }

}

// リモートオブジェクト
internal class MyRemoteObject: MarshalByRefObject, IRemoteObject {

  private int myvalue;

  public override object InitializeLifetimeService() {

    Console.WriteLine("MyRemoteObject.InitializeLifetimeService()");

    // このインスタンスに対するリースオブジェクトを取得
    ILease lease = (ILease)base.InitializeLifetimeService();

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

      // サンプルにあったこのコードでは繰り返し延長されない?
      // lease.InitialLeaseTime = TimeSpan.FromMilliseconds(60000);
      // lease.SponsorshipTimeout = TimeSpan.FromMilliseconds(60000);
      // lease.RenewOnCallTime = TimeSpan.FromMilliseconds(60000);

      // 代わりにスポンサーを設定
      m_Sponsor = new MySponsor();
      lease.Register(m_Sponsor);

    }

    return lease;

  }

  // リースを終了させる(スポンサーを停止)
  public void EndLease() {
    if ( m_Sponsor != null ) {
      Console.WriteLine("MyRemoteObject.EndLease()");
      m_Sponsor.CanRenewal = false;
    }
  }
  private MySponsor m_Sponsor;

  public MyRemoteObject(int val) {
    Console.WriteLine("MyRemoteObject.ctor(int)");
    myvalue = val;
  }

  public MyRemoteObject() {
    Console.WriteLine("MyRemoteObject.ctor()");
  }

  public void setValue(int newval) {
    Console.WriteLine("MyRemoteObject.setValue(): old {0} new {1}",myvalue,newval);
    myvalue = newval;
  }

  public int getValue() {
    Console.WriteLine("MyRemoteObject.getValue(): current {0}",myvalue);
    return myvalue;
  }

}

// サーバーエントリポイント
class ServerStartup {

  static void Main(string[] args) {

    Console.WriteLine ("ServerStartup.Main(): Server started");

    LifetimeServices.LeaseManagerPollTime = TimeSpan.FromMilliseconds(10);

    HttpChannel chnl = new HttpChannel(8080);
    ChannelServices.RegisterChannel(chnl);

    // ファクトリーのリモート定義(シングルトン)
    RemotingConfiguration.RegisterWellKnownServiceType(
      typeof(MyRemoteFactory),
      "factory.soap",
      WellKnownObjectMode.Singleton);

    // the server will keep running until keypress.
    Console.ReadLine();

  }

}



サーバーコンソールに出力された内容

ServerStartup.Main(): Server started
MyManager.getNewInstance() called
MyRemoteObject.ctor()
MyRemoteObject.InitializeLifetimeService()
MyRemoteObject.getValue(): current 0
MyRemoteObject.setValue(): old 0 new 1
MySponsor.Renewal() -- extend 1 min.
MySponsor.Renewal() -- extend 1 min.
MyRemoteObject.getValue(): current 1
MyRemoteObject.setValue(): old 1 new 2
MySponsor.Renewal() -- extend 1 min.
MySponsor.Renewal() -- extend 1 min.
MySponsor.Renewal() -- extend 1 min.
MySponsor.Renewal() -- extend 1 min.
MySponsor.Renewal() -- extend 1 min.
MyRemoteObject.getValue(): current 2
MyRemoteObject.setValue(): old 2 new 3
MySponsor.Renewal() -- extend 1 min.
MySponsor.Renewal() -- extend 1 min.
MySponsor.Renewal() -- extend 1 min.
MySponsor.Renewal() -- extend 1 min.
MySponsor.Renewal() -- extend 1 min.
MyRemoteObject.EndLease()
MySponsor.Renewal() -- end lease







クライアントコンソールに出力された内容

Client.Main(): Acquiring object from factory
Client.Main(): Sleeping 5 second
Client.Main() : Setting value 1
Client.Main(): Sleeping 400 second
Client.Main() : Setting value 2
Client.Main(): Sleeping 400 second
Client.Main() : Setting value 3
Client.Main(): Sleeping 400 second
Client.Main() : EndLease
Client.Main(): Sleeping 600 second
Client.Main() : Get value
Client.Main(). EXCEPTION
要求されたサービスが見つかりません

セリカ
会議室デビュー日: 2006/12/18
投稿数: 12
投稿日時: 2007-01-25 17:44
masaさん、ありがとうございます。
早速ためしてみます。(ちょっと時間をいただくかと思いますが・・・)

1

スキルアップ/キャリアアップ(JOB@IT)