WCF NetNamedPipeBinding确定客户端的进程ID

本文关键字:进程 ID 客户端 NetNamedPipeBinding WCF | 更新日期: 2023-09-27 18:21:06

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

WCF NetNamedPipeBinding确定客户端的进程ID

Bryan,

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

为了稍微扩展一点——当使用GetNamedPipeClientProcessId时,我们首先需要一个命名管道的句柄。由于WCF并没有使其特别容易找到(请参阅此处),因此我们需要对内存映射文件进行处理,以确定命名管道的GUID。Divi的答案是:通过程序获取命名管道的系统名称,演示如何获取该值。

一旦我们有了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年6月11日

我不确定你是否能够直接从管道中获得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);
        }
    }
}