![](/img/trans.png)
[英]How to detect client connection to a named pipe server using overlapped I/O?
[英]Reading named Pipe using overlapped/asynchronous i/o
我有一个来自服务的真正旧代码,该服务在消息模式 ( PIPE_TYPE_MESSAGE
) 中使用具有重叠 i/o ( FILE_FLAG_OVERLAPPED
) 的命名命名管道。
该代码执行以下操作:
ReadFile
用于 4 个字节,具有重叠的 i/o(标头 + 消息长度)。 客户端通过一次调用WriteFile
来编写此命令。ReadFile
以读取消息的 rest(具有已知长度)而不指定OVERLAPPED
结构。当我阅读文档时
重叠操作需要一个名为 pipe 的文件或使用 FILE_FLAG_OVERLAPPED 标志创建的通信设备。 当线程调用function(如ReadFile函数)执行重叠操作时,调用线程必须指定一个指向OVERLAPPED结构的指针。 (如果此指针为 NULL,则 function 返回值可能会错误地指示操作已完成。)
我必须假设这段代码将不起作用或至少被称为不正确的......
事实上,这段代码已经有 15 年的历史了,可以在数百台机器上运行,并且可以毫无问题地运行。
那么我是否必须告诉我的老板和同事这段代码有问题,它能工作只是运气,需要更正这段代码?
是的,此代码不正确但可以正常工作。 ReadFile
调用ZwReadFile
。 第 5 个参数 - IoStatusBlock - 指向IO_STATUS_BLOCK
结构的指针 - 是强制性的,并且对于任何文件都不能为 0。 对于任何 I/O 类型。 因此ReadFile
在调用ZwReadFile
时必须传递指向IO_STATUS_BLOCK
的指针。 如果您将非 0 指针传递给OVERLAPPED
- 它会将此指针作为IO_STATUS_BLOCK
给ZwReadFile
。 OVERLAPPED
的前 2 个成员对应于IO_STATUS_BLOCK
。 但是如果你在OVERLAPPED
的指针位置传递 0 - ReadFile
分配本地IO_STATUS_BLOCK iosb
变量并将其传递给ZwReadFile
。 IO_STATUS_BLOCK
memory 必须有效,直到 I/O 未完成。 因为在 I/O kernel 的末尾,将最终状态写入此 memory。从另一侧 - 如果您是IO_STATUS_BLOCK
的局部变量 - 它在ReadFile
返回后变得无效(指向堆栈中的任意 memory)。 如果是同步 I/O - 这里没问题,因为ReadFile
在 I/O 未完成之前不会返回。 但如果异步 I/O - 这是 UB - ReadFile
可以在 I/O 仍在进行时返回。 所以IO_STATUS_BLOCK
在 I/O 结束之前变得无效。 当 I/O 实际结束时 - 将在线程堆栈中的任意位置被覆盖 memory。 这可能没有任何影响或可能会破坏您的堆栈。 未定义。 取决于此时你所在的位置(哪个堆栈指针值)
看了多了文档,不得不说是的,代码可以说是不正确的。 特别是ReadFile
上的这些文档:
如果使用 FILE_FLAG_OVERLAPPED 打开 hFile 参数,则需要指向 OVERLAPPED 结构的指针,否则它可以是 NULL。
如果使用 FILE_FLAG_OVERLAPPED 打开 hFile,lpOverlapped 参数必须指向有效且唯一的 OVERLAPPED 结构,否则 function 会错误地报告读取操作已完成。
请记住,MS 文档会随着时间的推移而更新,并且在编写代码时文档可能不够清晰或不完整。
它可能恰好起作用,因为 pipe 处于消息模式。 首先使用消息模式管道的长度前缀 header 很奇怪,因为消息模式会为您处理消息边界。 在这种特定情况下,整个消息已经在本地操作系统中,因此不正确的同步读取总是会成功。
事实上,该协议(带有单独的标头)听起来像是设计用于字节 stream 抽象,例如字节模式 pipe 或 TCP/IP 连接。 该协议可能最初是为字节模式管道设计的,当它不工作时它们切换到消息模式管道(同步ReadFile
可能在字节模式 pipe 上表现出意外,因为消息可能尚未完全存在)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.