我正在编写一个通过命名管道与用户态应用程序通信的驱动程序。 userland应用程序通过调用CreateNamedPipe()创建命名管道,然后通过调用IOCTL将管道名称传递给驱动程序。然后驱动程序通过调用ZwCreateFile()来打开管道。
userland应用程序然后命中一个循环,该循环读取来自管道的请求,处理请求并将结果写回管道,即:
while(1) {
ReadFromPipe
ProcessRequest
WriteToPipe
}
驱动程序基本上将请求写入管道,然后直接回读答案:
WriteRequestToPipe
ReadAnswerFromPipe
我的问题是,如果在应用程序中发生WriteToPipe之前在驱动程序中发生ReadAnswerFromPipe,则ReadAnswerFromPipe永远不会返回。 所以基本上做了
WriteRequestToPipe
Sleep(10 seconds)
ReadAnswerFromPipe
解决了这个问题。
为什么我会看到这个?
澄清:我使用两个不同的单向管道,尽管应用程序最终成功调用WriteToPipe,但ReadAnswerFromPipe调用永远不会返回...
答案 0 :(得分:7)
由于命名管道在任何给定时间都支持单向通信,因此您必须使用2个管道(如已建议的)进行真正的异步访问,或者同步访问单个管道(如步话机)。 semaphore object应该很好用。如果只将CreateSemaphore()的Maximum Count参数设置为1,它将充当二进制信号量。然后,您可以ZwWaitForSingleObject()
在客户端和服务器上while(true)
消息循环内的信号量上{{1}},并且您将具有同步访问权限。
编辑:记得您正在编写驱动程序作为此服务器组件,因此您将需要特定于内核的函数和结构,即驱动程序端的KSEMAPHORE结构。
答案 1 :(得分:3)
管道通常被视为单向通信渠道。
我相信最简单的解决方案是创建两个管道:一个用于应用程序→驱动程序消息,另一个用于驱动程序→应用程序消息。
答案 2 :(得分:1)
不知道您正在撰写的Windows版本,或者您所处的开发环境,我不确定这一定会有所帮助,但可能会有所帮助。
如果您确保每次从驱动程序发送请求时都从用户应用程序获得响应,您可以考虑使用API函数TransactNamedPipe()(有关完整的使用文档,请参阅this page in the MSDN)。 / p>
它专门用于发送/接收,并将等到响应返回之前返回。
或者,您可以在'重叠'模式下使用此功能,在这种情况下,它会立即返回,之后您等待事件 - 您必须作为原始调用中'TransactionOverlapped'结构的一部分传入 - 要知道你已收到答案。
答案 3 :(得分:1)
最好使用IOCTL与userland进行通信。你为什么需要管道?
答案 4 :(得分:0)
ephemient是正确的。您可以坚持使用单个管道,但是您必须在两端之间同步读取和写入。添加的睡眠似乎对您有用,因为它允许在读取答案之前读取请求 - 但这很容易出错,因为一端的延迟可能会导致错误。