是否可以使用NetNamedPipeBinding作为绑定来确定连接到ServiceHost的客户端进程ID?
答案 0 :(得分: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);
}
}
}