【问题标题】:System.Management.ManagementEventWatcher - Recovering From DisconnectionSystem.Management.ManagementEventWatcher - 从断开连接中恢复
【发布时间】:2009-07-21 22:41:26
【问题描述】:

我正在尝试构建一个可以通过 WMI 监控多台远程计算机的应用程序。作为一名 C# 开发人员,我选择使用 System.Management 命名空间。

出于性能和可扩展性的原因,我更喜欢使用事件驱动的方法来收集信息,而不是基于轮询的方法。因此,我一直在研究 ManagementEventWatcher 类。

对于简单的监控任务,这个类似乎正是我想要的。我创建对象,为其提供 ManagementScope、EventQuery 和 EventWatcherOptions 参数,订阅 EventArrived 事件,并调用 Start 方法(下面的简化示例)。

  using SM = System.Management;

  ...

  SM.ManagementEventWatcher    _watcher;
  SM.ConnectionOptions         conxOptions;
  SM.ManagementScope           scope;
  SM.WqlEventQuery             eventQuery;
  SM.EventWatcherOptions       eventOptions;
  SM.EventArrivedEventHandler  handler;

  string  path = @"\\machine\root\cimv2";

  conxOptions = new SM.ConnectionOptions ();
  conxOptions.Username = user;
  conxOptions.Password = password;
  scope = new SM.ManagementScope (path, conxOptions);
  scope.Connect ();

  eventQuery = new SM.WqlEventQuery ("SELECT * FROM __InstanceCreationEvent WITHIN 10 WHERE TargetInstance ISA 'Win32_Process'");

  eventOptions = new SM.EventWatcherOptions ();
  eventOptions.Context.Add ("QueryName", "Process Query");

  _watcher = new SM.ManagementEventWatcher (scope, eventQuery, eventOptions);
  handler = new SM.EventArrivedEventHandler (HandleWMIEvent);
  _watcher.EventArrived += handler;
  _watcher.Start ();

  Console.WriteLine ("Press Any Key To Continue");
  Console.ReadKey ();

  _watcher.Stop ();
  _watcher.EventArrived -= handler;

我遇到的问题是很难检测到远程机器的连接何时已通过各种方式(机器重启、路由器故障、网线拔出等)中断。

ManagementEventWatcher 类似乎没有提供任何确定连接已丢失的方法,因为发生这种情况时不会触发 Stopped 事件。尽管链接断开,附加到 ManagementEventWatcher 的 ManagementScope 对象仍将 IsConnected 显示为 true。

有人对如何检查连接状态有任何想法吗?

此时我唯一能想到的就是使用 ManagementScope 对象定期对机器执行 WMI 查询并确保它仍然有效,尽管这只能检查本地->远程连接而不是对应的远程->本地连接。我想我可以查找另一个可以用来验证连接的 WMI 查询(假设查询有效),但这似乎比我应该做的工作更多。

【问题讨论】:

    标签: c# .net wmi monitoring


    【解决方案1】:

    WMI 中有两种事件消费者——临时的和永久的。您可能正在寻找的是永久事件订阅。这是 MSDN 上的简短介绍

    永久使用者是可以随时接收 WMI 事件的 COM 对象。永久事件使用者使用一组持久对象和过滤器来捕获 WMI 事件。与临时事件使用者一样,您设置了一系列 WMI 对象和过滤器来捕获 WMI 事件。当发生与过滤器匹配的事件时,WMI 会加载永久事件使用者并通知它有关该事件的信息。因为永久消费者是在 WMI 存储库中实现的,并且是在 WMI 中注册的可执行文件,所以永久事件消费者在创建后甚至在重新启动操作系统后,只要 WMI 正在运行,它就会运行并接收事件。有关详细信息,请参阅随时接收事件。

    这篇 MSDN 文章应该足以让您继续前进 http://msdn.microsoft.com/en-us/library/aa393014(VS.85).aspx

    但是,在我处理这个问题的情况下,我们选择轮询数据而不是创建一个永久消费者。另一种选择是监视某些事件(例如重新启动),然后重新注册您的临时事件使用者。

    【讨论】:

      【解决方案2】:

      查看这篇帖子here。它涵盖了如何使用 C# 检测何时插入可移动磁盘。应该与您提供的 WMI 代码内联。

      【讨论】:

        【解决方案3】:

        订阅NetworkAvailabilityChange 事件,这应该让您通过 NetworkAvailabilityEventArgs.IsAvailable 属性了解当前连接的状态。通过一些额外的工作,NetworkAddressChange 事件将让您了解网络上移动、更改地址等的机器。 . . System.Net.NetworkInformation 有很好的信息。 . .我假设你不介意使用 WMI 以外的东西来监控它。

        【讨论】:

          【解决方案4】:

          据我所知,当发生类似情况时,您应该会收到一个 ManagementException 类型的异常,其中包含 wbemErrCallCancelled WMI 错误代码 (0x80041032)。

          【讨论】:

          • 我发现,如果远程计算机上的 WMI 服务重新启动,则会触发 ManagementEventWatcher.Stopped 事件,但在任何其他情况下(例如重新启动、网络断开等),我什么也得不到。与此同时,我考虑订阅一个事件以提供一种我可以依赖的心跳形式。对于任何 WindowsXP 机器及更高版本,我可以使用“SELECT * FROM __InstanceModificationEvent WHERE TargetInstance ISA 'Win32_UTCTime' AND (TargetInstance.Seconds=0 OR TargetInstance.Seconds=30)”来提供 30 秒的心跳。恐怕这最终必须是我的答案。
          猜你喜欢
          • 1970-01-01
          • 2012-11-19
          • 2015-03-29
          • 1970-01-01
          • 2013-08-17
          • 1970-01-01
          • 1970-01-01
          • 2019-01-31
          • 1970-01-01
          相关资源
          最近更新 更多