布莱恩,
只是花了几个小时研究这个,我比较肯定这是不可能的。无论您离管道多近,使用您评论中引用的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);
}
}
}