.NET中的NamedPipeClientStream
类存在一个问题,即您无法使用PipeDirection.In
创建此类的示例,然后成功地将ReadMode
更改为PipeTransmissionMode.Message
。
尝试这样做将引发UnauthorizedAccessException
。尽管管道通常用于进程之间的通信,但单个进程中的这个简单示例显示了问题:
var pipeOut = new NamedPipeServerStream("SomeNamedPipe",
PipeDirection.Out,
1,
PipeTransmissionMode.Message);
var pipeIn = new NamedPipeClientStream(".",
"SomeNamedPipe",
PipeDirection.In);
pipeIn.Connect();
pipeIn.ReadMode = PipeTransmissionMode.Message;
此代码将在尝试设置ReadMode属性时引发UnauthorizedAccessException
。
在搜索关于这个问题的信息时,我在其他地方找到了它的参考资料,比如这里:
- Named pipes issue: System.UnauthorizedAccessException: Access to the path is denied.
- WPF - Messaging using Windows Pipes protocol
- PipeTransmissionMode.Message: How do .NET named pipes distinguish between messages?
所有这些帖子都提到这是“怪异的”,“奇怪的”,等等,但没有解释“为什么”它不工作,而且都给予了相同的解决方案,“出于某种奇怪的原因”设置管道方向为InOut
使它工作。
这确实使它工作,但它需要从根本上改变管道的定义,在两端,全双工,而不是在一个方向上,我认为这是一个非常糟糕的方法,除非你能够改变客户端和服务器,这甚至可能是不可能的。
我的问题是,为什么在入站管道上启用消息模式会导致异常,是否有比将管道更改为双向模式更好的方法来解决这个问题?
1条答案
按热度按时间8ehkhllq1#
查看Microsoft参考源代码,我可以看到设置
ReadMode
属性只是调用win32SetNamedPipeHandleState
函数来执行操作,此调用的错误作为异常引发。对于只写管道或读/写管道,句柄必须具有对命名管道的GENERIC_WRITE访问权限;对于只读管道,句柄必须具有GENERIC_READ和FILE_WRITE_ATTRIBUTES访问权限。
问题就在这里。
如果我们查看接受
PipeDirection
设置的NamedPipeClientStream的构造函数,我们会发现它们只请求PipeDirection.In
的GENERIC_READ
访问权限,以及PipeDirection.Out
的GENERIC_WRITE
访问权限这意味着以Out
或InOut
模式打开的任何管道都将工作,因为GENERIC_WRITE
访问对于那些情况是足够的,但是我们需要GENERIC_READ
和FILE_WRITE_ATTRIBUTES
作为只读管道,而NamedPipeClientStream
类从不请求。这是类中的一个缺陷,应该由Microsoft更正。我在这里提交了一份关于Microsoft Connect的错误报告:
https://connect.microsoft.com/VisualStudio/feedback/details/1825187
如果您自己遇到这个问题,请投赞成票,这可能有助于加快修复速度。
在修复之前(截至2017年3月没有),可以通过对
NamedPipeClientStream
使用不同的构造函数来完全解决这个问题。构造函数有一个重载,它接收
PipeAccessRights
枚举而不是PipeDirection
枚举,在这里你可以指定你想要为句柄获得的访问权限的特定组合。构造函数然后从指定的访问权限组合中导出管道的方向(如果指定了ReadData
,则为In
;如果指定了WriteData
,则为Out
";如果同时指定了InOut
和WriteData
,则为InOut
)。这意味着,你可以解决这个问题,而不必让你的管道全双工,通过简单地改变一个构造函数行如下:
改为:
如果您使用此备用构造函数作为建议的解决方法,则结果将与从构造函数的第一种形式获得的结果相同且无法区分,例外情况是将获得此附加访问权限,以便可以启用消息模式。