5

サーバーがサーバー間でメッセージを交換するパッシブレプリケーションを使用するプロジェクトを開発しています。各サーバーの場所は、他のすべてのサーバーによって既知です。

そのため、サーバーが起動すると、まだ起動していない可能性のある他のサーバーをチェックすることがあります。を呼び出すときに、オブジェクトのメソッドを呼び出すことによって他のサーバーがダウンしていることを確認し、 (以下の例のように)Activator.GetObjectを期待する唯一の方法ですか?IOException

try 
{
    MyType replica = (MyType)Activator.GetObject(
    typeof(IMyType),
    "tcp://localhost:" + location + "/Server");

    replica.ping();
}
catch (IOEXception){} // server is down

私はこれを行い、ほとんどの場合は動作しますが (遅い場合でも)、NegotiateStream.ProcessReadプロセス中に呼び出されたメソッドでブロックされることがありますが、その理由がわかりません...

4

2 に答える 2

3

サーバーがダウンしている場合、タイムアウトは常に遅くなります (TcpChannel を使用すると、.NET Remoting でタイムアウトを適切に設定できません)。以下は、私の Ping 関数の使用方法の回避策です (ニーズによっては少し複雑になる可能性があるため、重要な部分について説明します)。

  [System.Diagnostics.DebuggerHidden] // ignore the annoying breaks when get exceptions here.
  internal static bool Ping<T>(T svr)
  {
     // Check type T for a defined Ping function
     if (svr == null) return false;
     System.Reflection.MethodInfo PingFunc = typeof(T).GetMethod("Ping");
     if (PingFunc == null) return false;

     // Create a new thread to call ping, and create a timeout of 5 secons
     TimeSpan timeout = TimeSpan.FromSeconds(5);
     Exception pingexception = null;
     System.Threading.Thread ping = new System.Threading.Thread(
        delegate()
        {
           try
           {
              // just call the ping function
              // use svr.Ping() in most cases
              // PingFunc.Invoke is used in my case because I use
              // reflection to determine if the Ping function is
              // defined in type T
              PingFunc.Invoke(svr, null);
           }
           catch (Exception ex)
           {
              pingexception = ex;
           }
        }
     );

     ping.Start(); // start the ping thread.
     if (ping.Join(timeout)) // wait for thread to return for the time specified by timeout
     {
        // if the ping thread returned and no exception was thrown, we know the connection is available
        if (pingexception == null)
           return true;
     }

     // if the ping thread times out... return false
     return false;
  }

コメントがここで何をするかを説明してくれることを願っていますが、関数全体の内訳を説明します。興味がない場合は、ping スレッドについて説明するところまでスキップしてください。

DebuggerHidden 属性

DebuggerHidder 属性を設定したのは、デバッグ時に ping スレッドで常に例外がスローされる可能性があり、それらが想定されているためです。この関数のデバッグが必要になった場合、これをコメントアウトするのは簡単です。

リフレクションとジェネリック型を使用する理由

「svr」パラメーターは、Ping 機能を持つタイプであることが期待されます。私の場合、共通の Ping 機能を使用して、いくつかの異なるリモート インターフェイスをサーバーに実装しています。このようにして、型をキャストしたり指定したりする必要なく、Ping(svr) を呼び出すことができます (リモート オブジェクトがローカルで「オブジェクト」としてインスタンス化されていない限り)。基本的に、これは構文上の便宜のためです。

ピンスレッド

許容可能なタイムアウトを決定するために任意のロジックを使用できます。私の場合、5 秒が適切です。値が 5 秒の TimeSpan 'timeout' と例外 pingexception を作成し、'svr.Ping()' を呼び出そうとする新しいスレッドを作成し、'svr.Ping()' を呼び出したときにスローされる例外に 'pingexception' を設定します。 Ping()'.

「ping.Start()」を呼び出したら、すぐにブール型メソッド ping.Join(TimeSpan) を使用して、スレッドが正常に戻るのを待つか、指定された時間内にスレッドが戻らない場合は先に進みます。ただし、スレッドの実行が終了しても例外がスローされた場合でも、リモート オブジェクトとの通信に問題があったため、Ping が true を返すことは望ましくありません。これが、'pingexception' を使用して、svr.Ping() の呼び出し時に例外が発生していないことを確認する理由です。最後に 'pingexception' が null の場合は、true を返しても安全であることがわかります。

ああ、あなたが最初に尋ねた質問に答えるために (....プロセス中に NegotiateStream.ProcessRead と呼ばれるメソッドでブロックされることがあり、その理由がわかりません...)、タイムアウトを把握できませんでした.NET Remoting の問題があるため、このメソッドは、.NET Remoting のニーズに合わせて焼き付けてクリーンアップしたものです。

于 2013-08-21T16:05:25.117 に答える
1

これの改良版をジェネリックで使用しました。

    internal static TResult GetRemoteProperty<T, TResult>(string Url, System.Linq.Expressions.Expression<Func<T, TResult>> expr)
    {
        T remoteObject = GetRemoteObject<T>(Url);
        System.Exception remoteException = null;
        TimeSpan timeout = TimeSpan.FromSeconds(5);
        System.Threading.Tasks.Task<TResult> t = new System.Threading.Tasks.Task<TResult>(() => 
        {
            try
            {
                if (expr.Body is System.Linq.Expressions.MemberExpression)
                {
                    System.Reflection.MemberInfo memberInfo = ((System.Linq.Expressions.MemberExpression)expr.Body).Member;
                    System.Reflection.PropertyInfo propInfo = memberInfo as System.Reflection.PropertyInfo;
                    if (propInfo != null)
                        return (TResult)propInfo.GetValue(remoteObject, null);
                }
            }
            catch (Exception ex)
            {
                remoteException = ex;
            }
            return default(TResult);
        });
        t.Start();
        if (t.Wait(timeout))
            return t.Result;
        throw new NotSupportedException();
    }

    internal static T GetRemoteObject<T>(string Url)
    {
        return (T)Activator.GetObject(typeof(T), Url);
    }
于 2013-10-25T13:01:54.527 に答える