问题: 有没有办法快速检查特定管道名称是否托管在会话 0 中 - 最好是在 ServiceHost.Open 调用期间?
场景:
两个进程 PipeHost 和 PipeUser 正在尝试通过名称为 PeacePipe 的管道在系统上进行通信。它们不需要以特殊权限启动。
PipeHost 已启动并托管 PeacePipe,没有任何问题。
PipeUser 已启动并连接到 PeacePipe,没有任何问题。
PipeUser 尝试通过 PeacePipe 与 PipeHost 进行通信,它发送消息,但 PipeHost 看不到任何内容。
事实上 PipeUser 连接到 DifferentPipeHostInSession0,它在提升的(或服务)进程中托管具有相同名称的管道(但操作系统创建不同的管道)。
背景:
当选定的管道名已被托管时,ServiceHost.Open应该抛出AddressAlreadyInUseException。
但是,如果管道托管在会话 0 中并且您尝试在不同会话中托管相同的管道,则不会抛出此错误。由于 Windows 命名管道通常不能跨会话使用。除了会话 0 中托管的管道之外。任何进程都可以连接到此类管道。这可能会导致上述情况。
代码:
[ServiceContract]
public interface IService
{
[OperationContract]
void Ping();
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple, IncludeExceptionDetailInFaults = true)]
public class Service: IService
{
public void Ping()
{
Console.WriteLine("Client Pinged me");
}
}
private static readonly Uri _pipeUri = new Uri("net.pipe://localhost/aaa");
private static readonly Binding _pipeBinding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);
static void PipeHostTest()
{
ServiceHost serviceHost = new ServiceHost(new Service(), _pipeUri);
serviceHost.AddServiceEndpoint(typeof(IService), _pipeBinding, "");
try
{
//Fail here if same pipe already opened - even in Global space
serviceHost.Open();
Console.WriteLine("OPENED");
}
catch (AddressAlreadyInUseException e)
{
Console.WriteLine(e);
throw;
}
Console.ReadKey();
}
static void PipeClient()
{
ChannelFactory<IService> channelFactory =
new ChannelFactory<IService>(_pipeBinding, new EndpointAddress(_pipeUri));
var proxy = channelFactory.CreateChannel();
proxy.Ping();
}
static void Main(string[] args)
{
if (args.Any())
{
PipeClient();
}
else
{
PipeHostTest();
}
}
在不提升参数的情况下运行一次,在不提升参数的情况下运行一次。两个进程都将托管具有相同名称的管道 - 但它们是不同的管道。 然后使用任意参数运行一次。客户端进程将连接到提升进程托管的管道。
可能的解决方案: 在全局会话中使用命名互斥体
new Mutex(true, "Global\\MutexForMyPipeName", out createdNew)
来查看是否有另一个进程尝试执行相同的操作。
然而,即使管道位于两个不冲突的不同会话中,这也会取消资格。
最好是 ServiceHost.Open 会为我处理这个问题,因为我使用多种绑定类型(net.tcp、net.pipe、net.udp)并且具有用于创建和托管 ServiceHost 的单个代码。 NamedPipes 是唯一可以允许创建新主机而不会出现 AddressAlreadyInUseException 异常的管道,而地址实际上已在使用中。
管道不像其他内核对象那样具有命名空间。
同一管道的多个服务器是一个“功能”,请参阅 CreateNamedPipe
nMaxInstances
。