【问题标题】:How to communicate with a windows service?如何与 Windows 服务通信?
【发布时间】:2011-05-25 23:20:09
【问题描述】:

我想创建一个 Windows 服务来验证数据并从另一个 Windows 应用程序访问它,但我是服务新手,不知道如何开始。

因此,当服务运行时,Windows 应用程序应该以某种方式连接到服务,发送一些数据并获得响应,无论是真还是假。

【问题讨论】:

    标签: c# windows-services ipc


    【解决方案1】:

    您的服务在处理过程中可以将事件添加到 EventLog。

    您可以创建另一个与服务并行运行的控制台应用程序,并使用事件处理机制侦听该 EventLog:

    var log= new EventLog("[name of the eventlog]");
    log.EnableRaisingEvents = true;
    log.EntryWritten += Log_EntryWritten;
    

    那你马上处理:

    private static void Log_EntryWritten(object sender, System.Diagnostics.EntryWrittenEventArgs e)
    {
        Console.WriteLine("Event detected !");
    }
    

    您可以阅读 EntryWrittenEventArgs 对象以获取所有事件详细信息,并在控制台应用程序中显示您想要的内容。如果您停止控制台应用程序,服务会继续运行,并且仍会记录到事件日志中。

    【讨论】:

    • 嗅探事件日志以在应用程序组件之间传输业务数据可能不是最糟糕的想法,但它已经接近了。
    【解决方案2】:

    我可以通过以下方式成功处理(几乎)与您相同的问题:

    在您的 Class : ServiceBase 中,代表您的 Service 类,您可能有:

    public Class () //constructor, to create your log repository
        {
          InitializeComponent();
    
          if (!System.Diagnostics.EventLog.SourceExists("YOURSource"))
          {
            System.Diagnostics.EventLog.CreateEventSource(
               "YOURSource", "YOURLog");
          }
          eventLog1.Source = "YOURSource";
          eventLog1.Log = "YOURLog";
        }
    

    现在,实施:

    protected override void OnStart(string[] args)
    {...}
    

    protected override void OnStop()
    {...}
    

    处理自定义命令调用:

    protected override void OnCustomCommand(int command)
        {
          switch (command)
          {
            case 128:
              eventLog1.WriteEntry("Command " + command + " successfully called.");
              break;
            default:
              break;
          }
        }
    

    现在,在您将调用 Windows 服务的应用程序中使用它:

    枚举来引用您的方法:(请记住,服务自定义方法始终接收 int32(128 到 255)作为参数,使用枚举可以更容易记住和控制您的方法

    private enum YourMethods
      {
        methodX = 128
      };
    

    调用特定方法:

    ServiceController sc = new ServiceController("YOURServiceName", Environment.MachineName);
    ServiceControllerPermission scp = new ServiceControllerPermission(ServiceControllerPermissionAccess.Control, Environment.MachineName, "YOURServiceName");//this will grant permission to access the Service
        scp.Assert();
        sc.Refresh();
    
        sc.ExecuteCommand((int)YourMethods.methodX);
    

    这样做,您可以控制您的服务。

    Here您可以查看如何创建和安装 Windows 服务。 More 关于 ExecuteCommand 方法。

    祝你好运!

    【讨论】:

    • 有没有办法可以向服务发送除 int 以外的内容,比如字符串?以及如何在我的应用程序中获取返回值(由服务发送)
    • @mrid 恐怕你这种交流方式是不可能的
    【解决方案3】:

    在旧版本的 Windows 中,您可以将 Windows 服务配置为与桌面交互。这允许您将用户界面元素直接添加到可以呈现给用户的服务中。从 Windows Vista 开始,服务不能再直接与用户交互,即没有用户界面。

    为此,您要做的是编写您的 Windows 服务一个前端 Windows 应用程序。为了提供两者之间的沟通桥梁,我强烈建议使用Windows Communication Foundation (WCF)。

    要创建 C# Windows 服务,您可以按照here 的分步说明进行操作。

    【讨论】:

      【解决方案4】:

      如果您使用的是 .Net Framework 4,那么内存映射文件提供了一种实现跨进程通信的相当简单的方法。

      它相当简单,并且在文档中得到了很好的描述,并且避免了使用 WCF 或其他基于连接/远程处理的交互或将共享数据写入中心位置的开销(在运行时以及开发工作方面)轮询(数据库、文件等)。

      有关概述,请参阅here

      【讨论】:

        【解决方案5】:

        将其视为远程数据库所有者。假设您有 1 个数据库,但有 10 个应用程序需要来自数据库的不同数据,而且您不想将所有数据开放给每个应用程序。此外,您的应用程序将独立于您的数据库,您的数据层将只在您的服务中实现,您的应用程序将不包含该逻辑。您可以编写服务并将您的服务开放给其他应用程序。

        How to write your first windows service可以帮到你。

        【讨论】:

          【解决方案6】:

          为此,我们使用命名管道。但是我们的客户端是用 C++ 实现的。如果您的服务和应用程序是在 .Net 中实现的,则可以使用 .Net 远程处理。

          【讨论】:

          • .NET Remoting 已被 WCF 取代。
          • @Matt Davis - 并非所有远程使用场景都是如此。 WCF 中没有与二进制远程处理 MarshalByRefObject 对象等效的 WCF(这可能是解决此问题的最佳远程解决方案)。 WCF 取代了许多用例(但不是全部)的远程处理。
          • @Rob Levine,虽然在 WCF 中确实没有与 MarshalByRefObject 方案等效的方案,但在 WCF 框架中仍有解决此问题的方法。 MSDN 网站特别指出 .NET Remoting 是一项为向后兼容而维护的遗留技术,不推荐用于新开发。 msdn.microsoft.com/en-us/library/kwdt6w2k.aspx
          • @Matt Davis - 当然对于分布式应用程序来说,WCF 是前进的方向,这也是大多数人想要使用远程处理的方式。即使最初的远程处理被认为是遗留的,我仍然认为有一部分功能无法在 WCF 中轻松复制,因此 WCF 不能替代。我很想知道您对缺少 MarhsalByRefObject(即通过引用语义)远程客户端的“解决方法”有什么想法,因为我需要它的几次,我从来没有找到等效的。话虽如此,我可能会遗漏一些东西。
          【解决方案7】:

          您可以通过将服务托管 WCF 服务并从您的应用程序连接到它来非常轻松地完成此操作。

          【讨论】:

          • 这可能有效,但在执行此操作时需要考虑许多安全隐患。你现在有一个开放端口监听的服务——你如何验证谁在连接?您是否受到恶意连接的保护?您可能需要升级到 NETWORK SERVICE 或类似的权限才能打开连接,而您的服务可能不需要此级别的权限。总的来说 - 如果有其他更简单、更安全的选择,我会在实施之前仔细考虑。
          • @Rob,您不必让服务在 tcp 端口上侦听。 WCF 可以使用命名管道在同一台机器上的应用程序之间进行通信。当然,如果桌面应用程序在另一台机器上,你必须有一个开放的端口,但我认为这种情况并非如此。
          • @jlafay - 关于命名管道的公平点 - 你是对的,但对于任何面向连接的方法,你都需要考虑许多安全隐患。
          • 即使在NetTcpBinding 内,您也可以使用本地主机地址来限制对本地机器的访问。虽然一旦跨越机器边界就会产生安全隐患,但事实仍然是 WCF 使分布式操作成为可能,而内存映射解决方案则排除了它。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多