【问题标题】:WCF NetNamedPipeBinding Determine Process ID Of ClientWCF NetNamedPipeBinding 确定客户端的进程 ID
【发布时间】:2015-11-10 05:49:52
【问题描述】:

是否可以使用 NetNamedPipeBinding 作为绑定来确定连接到 ServiceHost 的客户端进程 ID?

【问题讨论】:

  • 客户端连接后不能通过管道从客户端发送数据吗?
  • 我需要“服务器”来确定 PID,假设我们不能信任客户端。我知道我可以使用link 从 NamedPipeStreamServer 获取 PID。所以我认为使用 WCF 命名管道服务器可能是可能的。
  • 明白了,我明天看看能不能挖点东西。

标签: c# wcf


【解决方案1】:

布莱恩,

只是花了几个小时研究这个,我比较肯定这是不可能的。无论您离管道多近,使用您评论中引用的GetNamedPipeClientProcessId 似乎总是返回主机PID。

稍微扩展一下——当使用GetNamedPipeClientProcessId 时,我们首先总是需要一个命名管道的句柄。由于 WCF 并没有让这变得特别容易找到(请参阅here),我们需要对内存映射文件进行按摩以确定命名管道的 GUID。 Divi 在这里的回答:Programically get the system name of named pipe 演示了如何获取这个值。

一旦我们有了 GUID 值,我们就可以像这样实际使用GetNamedPipeClientProcessId(请原谅废话代码):

// Real name of the named pipe, thanks Divi!
string pipeAccess = String.Format(@"\\.\pipe\{0}", Program.pipeGuid);

// Get our handle to the named pipe
IntPtr pipe = CreateFile(pipeAccess, FileAccess.ReadWrite,
    0, IntPtr.Zero, FileMode.Open, FileAttributes.Normal, IntPtr.Zero);

uint pid = 0;
GetNamedPipeClientProcessId(pipe, out pid);
Console.WriteLine("Real client PID: {0}", pid);

我的第一个想法是直接在OperationContract 函数中运行上述代码——不幸的是,它返回的是主机的 PID,而不是客户端的 PID。继续前进,我试图找到有关GetNamedPipeClientProcessId 的更多信息,但只能确定它返回存储在与命名管道关联的内核结构中的信息——我无法找到更多关于值的方式/位置/原因的信息设置。

由于 WCF 将字节直接编组到 Message 对象中,我认为我们可能需要更接近管道才能返回正确的客户端 PID。实现一个 非常 简单的自定义消息编码器并尝试像这样提取 PID:

public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager, string contentType)
{
    string pipeAccess = String.Format(@"\\.\pipe\{0}", Program.pipeGuid);

    IntPtr pipe = CreateFile(pipeAccess, FileAccess.ReadWrite,
        0, IntPtr.Zero, FileMode.Open, FileAttributes.Normal, IntPtr.Zero);

    uint pid = 0;
    GetNamedPipeClientProcessId(pipe, out pid);
    Console.WriteLine("Real client PID: {0}", pid);

    return _encoder.ReadMessage(buffer, bufferManager, contentType);
}

同样不成功,再次返回主机的 PID。总的来说,我不确定是否有办法在使用 WCF 时实际提取这些信息。如果其他人能找到一种方法来做到这一点,我也很想知道。也许基于 NetNamedPipeBinding 的自定义绑定会起作用。

原始答案 - 2015 年 11 月 6 日

我不确定您是否能够直接从管道中获取 PID。我相信最简单的方法如下所示......

服务器:

namespace WCFServer
{
    [ServiceContract]
    public interface IUtils
    {
        [OperationContract]
        void PostPID(int value);
    }

    public class Utils : IUtils
    {
        public void PostPID(int value)
        {
            // Do something with value here
            Console.WriteLine(value);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            using (ServiceHost host = new ServiceHost(
              typeof(Utils),
              new Uri[]{
          new Uri("net.pipe://localhost")
        }))
            {
                host.AddServiceEndpoint(typeof(IUtils),
                  new NetNamedPipeBinding(),
                  "Pipepipe");

                host.Open();

                Console.WriteLine("Service is available. " +
                  "Press <ENTER> to exit.");
                Console.ReadLine();

                host.Close();
            }
        }
    }
}

还有客户:

namespace WCFClient
{
    [ServiceContract]
    public interface IUtils
    {
        [OperationContract]
        void PostPID(int value);
    }

    class Program
    {
        static void Main(string[] args)
        {
            ChannelFactory<IUtils> pipeFactory =
              new ChannelFactory<IUtils>(
                new NetNamedPipeBinding(),
                new EndpointAddress(
                  "net.pipe://localhost/Pipepipe"));

            IUtils pipeProxy =
              pipeFactory.CreateChannel();

            pipeProxy.PostPID(Process.GetCurrentProcess().Id);
        }
    }
}

【讨论】:

  • 如果您很好奇,您的尝试失败了,因为您对第二个具有相同命名管道名称的管道实例进行了第二次连接,并查询了有关此第二次连接的信息。您需要获取 WCF 正在使用的管道连接的服务器端的实际 HANDLE。客户端 PID 是每个连接而不是每个命名管道名称。 TCP 类比是使用一个全新的套接字来建立到同一个 TCP 端口的新连接。
  • 换句话说,“Get our handle to the named pipe”的评论是不正确的。
猜你喜欢
  • 1970-01-01
  • 2011-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-09
相关资源
最近更新 更多