2

我正在编写一个通过命名管道与用户级应用程序通信的驱动程序。用户态应用程序通过调用 CreateNamedPipe() 创建命名管道,然后通过调用 IOCTL 将管道名称传递给驱动程序。然后驱动程序通过调用 ZwCreateFile() 打开管道。

用户态应用程序然后点击一个循环,从管道读取请求,处理请求并将结果写回管道,即:

while(1) {
ReadFromPipe
ProcessRequest
WriteToPipe
}

驱动程序基本上将请求写入管道,然后直接读回答案:

WriteRequestToPipe
ReadAnswerFromPipe

我的问题是,如果 ReadAnswerFromPipe 在应用程序中发生 WriteToPipe 之前发生在驱动程序中,则 ReadAnswerFromPipe 永远不会返回。所以基本上在做

WriteRequestToPipe
Sleep(10 seconds)
ReadAnswerFromPipe

解决问题。

为什么我会看到这个?

澄清:我正在使用两个不同的单向管道,尽管应用程序最终成功调用了 WriteToPipe,但 ReadAnswerFromPipe 调用永远不会返回......

4

5 回答 5

7

由于命名管道在任何给定时间都支持单向通信,因此您必须使用 2 个管道(如前所述)进行真正的异步访问,或者同步访问单个管道(如对讲机)。信号量对象应该可以很好地解决这个问题。如果您只是将 CreateSemaphore() 的最大计数参数设置为 1,它将充当二进制信号量。然后,您可以在客户端和服务器上ZwWaitForSingleObject()的消息循环中使用该信号量,您将获得同步访问。while(true)

编辑:刚刚记得您正在编写一个驱动程序作为它的服务器组件,因此您将需要内核特定的函数和结构,即驱动程序端的KSEMAPHORE结构。

于 2009-11-22T03:48:15.280 回答
3

管道通常被认为是单向通信通道。

我相信对您来说最简单的解决方案是创建两个管道:一个用于应用程序→驱动程序消息,一个用于驱动程序→应用程序消息。

于 2009-11-20T22:57:07.727 回答
1

最好使用 IOCTL 与用户空间进行通信。为什么需要管道?

于 2009-11-23T08:35:29.917 回答
1

不知道您正在为哪个版本的 Windows 编写,或者您所处的开发环境,我不确定这一定会有所帮助,但它可能会有所帮助。

如果保证每次从驱动程序发送请求时都能从用户应用程序中获得响应,则可以考虑使用 API 函数 TransactNamedPipe()(请参阅MSDN 中的此页面以获取完整的使用文档)。

它专门用于发送/接收,并将等到响应返回后再返回。

或者,您可以在“重叠”模式下使用此函数,在这种情况下,它将立即返回,之后您等待一个事件 - 您必须在原始调用中作为“TransactionOverlapped”结构的一部分传入 - 要知道你已经收到你的答案。

于 2009-11-20T23:22:40.853 回答
0

ehemient 是正确的。您可以坚持使用单个管道,但是您必须在两端之间同步读取和写入。添加的睡眠似乎对您有用,因为它允许在读取答案之前读取请求 - 但这很容易出错,因为一端的延迟可能会导致错误。

于 2009-11-20T23:21:15.863 回答