代码之家  ›  专栏  ›  技术社区  ›  Shrike

通过命名管道从windows服务(会话0)连接到桌面应用(会话1)

  •  7
  • Shrike  · 技术社区  · 14 年前

    鉴于 :
    -应用程序-桌面GUI(WPF).NET应用程序
    -windows服务监视应用程序(.NET)

    windows服务会定期“ping”应用程序以确保其正常运行(如果不是,winservice将重新启动它)。
    我打算通过命名管道实现“ping”。为了使事情更简单,我决定用WCF来做。应用程序托管一个WCF服务(一个操作Ping返回一些内容)。windows服务是此WCF服务的客户端,基于计时器定期调用它。

    这都在Windows7中。
    Windows服务正在LocalService下运行(在会话0中)。
    桌面应用程序正在当前登录用户(在会话1中)下运行。

    问题 :
    Windows服务无法看到在桌面应用程序中创建并正在侦听的WCF终结点(具有NetNamedPipeBinding)。这意味着在通过wcf代理进行调用时,我会得到此异常:“在本地计算机上找不到管道终结点'net.pipe://localhost/HeartBeat'”

    我确信代码是正确的,因为另一个桌面应用程序(在会话1中)可以看到端点。

    显然,这里我要处理一些Win32系统对象隔离的安全问题。 但我相信应该有办法解决我遇到的限制。
    我可以牺牲WCF方法,走原始的NamedPipe之路。

    2 回复  |  直到 14 年前
        1
  •  6
  •   Chris Dickson    14 年前

    一个更简单的解决方案可能是与承载WCF服务的Windows服务一起使用WCF双工协议。客户端应用程序将在服务启动时调用该服务的操作来注册自身。然后,Ping将是一个由客户端回调契约上的服务定期调用的操作,应用程序将对此做出响应。

    服务可见性是这样工作的,因为Windows服务可以使用SeCreateGlobalPrivilege运行,因此服务发布管道名称所通过的共享内存对象可以在全局内核命名空间中创建,对其他会话可见。交互式应用程序在Windows7中无法轻松获得该权限,因此此类应用程序中的WCF服务会返回到在本地内核命名空间中发布管道,该命名空间仅在它们自己的会话中可见。

        2
  •  5
  •   Shrike    14 年前

    最后我找到了一个解决方案-直接使用System.IO.Pipes中的命名管道。WCF的管道支持实现似乎不使用System.IO.pipes。

    服务器 :

    using (var pipeServer = new NamedPipeServerStream("mypipe", PipeDirection.Out, 1))
    {
        try
        {
            while (true)
            {
                // #1 Connect:
                try
                {
                    pipeServer.WaitForConnection();
                }
                catch (ObjectDisposedException)
                {
                    yield break;
                }
                if (ae.IsCanceled())
                    return;
    
                // #2: Sending response:
                var response = Encoding.ASCII.GetBytes(DateTime.Now.ToString());
                try
                {
                    pipeServer.Write(response, 0, response.Length);
                }
                catch (ObjectDisposedException)
                {
                    return;
                }
    
                // #3: Disconnect:
                pipeServer.Disconnect();
            }
        }
        finally
        {
            if (pipeServer.IsConnected)
                pipeServer.Disconnect();
        }
    }
    

    顾客 :

    using (var pipeClient = new NamedPipeClientStream(".", "mypipe", PipeDirection.In))
    {
        try
        {
            try
            {
                pipeClient.Connect(TIMEOUT);
            }
            catch(TimeoutException ex)
            {
                // nobody answers to us
                continue;
            }
            using (var sr = new StreamReader(pipeClient))
            {
                string temp;
                while ((temp = sr.ReadLine()) != null)
                {
                    // got response
                }
            }
        }
        catch(Exception ex)
        {
            // pipe error
            throw;
        }
    }