调用Activator.GetObject后检查对象是否存在

Man*_*eis 5 .net c# .net-remoting

我正在开发一个带有被动复制的项目,其中服务器之间交换消息.每台服务器的位置都是众所周知的.

因此,当服务器启动时,它可能会检查其他可能尚未启动的服务器.当我调用时Activator.GetObject,它是通过调用对象上的方法来查明其他服务器已关闭的唯一方法,并且期望IOException(例如下面的示例)?

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

    replica.ping();
}
catch (IOEXception){} // server is down
Run Code Online (Sandbox Code Playgroud)

我这样做,它大部分时间都有效(即使很慢),但有时会阻塞NegotiateStream.ProcessRead在此过程中调用的方法,我无法理解为什么......

Ben*_*est 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;
  }
Run Code Online (Sandbox Code Playgroud)

希望这些评论能解释我在这里所做的事情,但我会给你整个功能的细分。如果您不感兴趣,请跳到我解释 ping 线程的地方。

调试器隐藏属性

我设置 DebuggerHidder 属性是因为在调试时,ping 线程中可能会不断地在此处抛出异常,并且它们是预期的。如果需要调试此函数,很容易将其注释掉。

为什么我使用反射和泛型类型

“svr”参数应为具有 Ping 功能的类型。就我而言,我在服务器上实现了几个不同的远程接口,并具有通用的 Ping 功能。通过这种方式,我可以只调用 Ping(svr) 而无需强制转换或指定类型(除非远程对象在本地实例化为“对象”)。基本上,这只是为了语法方便。

Ping 线程

您可以使用任何您想要的逻辑来确定可接受的超时,在我的例子中,5 秒就很好。我创建一个值为 5 秒的 TimeSpan“超时”、一个 Exception pingException,并创建一个尝试调用“svr.Ping()”的新线程,并将“pingException”设置为调用“svr”时引发的任何异常。平()'。

一旦我调用“ping.Start()”,我立即使用布尔方法 ping.Join(TimeSpan) 等待线程成功返回,或者如果线程没有在指定的时间内返回,则继续前进。但是,如果线程执行完毕但抛出异常,我们仍然不希望 Ping 返回 true,因为与远程对象通信时出现问题。这就是为什么我使用“pingException”来确保调用 svr.Ping() 时不会发生异常。如果“pingException”最后为空,那么我知道我可以安全地返回 true。

哦,为了回答您最初提出的问题(...有时它会在此过程中阻塞名为 NegotiateStream.ProcessRead 的方法,我不明白为什么...),我一直无法弄清楚超时.NET Remoting 的问题,所以这个方法是我为我们的 .NET Remoting 需求而烘焙和清理的方法。