繁体   English   中英

使用重叠/异步 i/o 读取名为 Pipe

[英]Reading named Pipe using overlapped/asynchronous i/o

我有一个来自服务的真正旧代码,该服务在消息模式 ( PIPE_TYPE_MESSAGE ) 中使用具有重叠 i/o ( FILE_FLAG_OVERLAPPED ) 的命名命名管道。

该代码执行以下操作:

  1. ReadFile用于 4 个字节,具有重叠的 i/o(标头 + 消息长度)。 客户端通过一次调用WriteFile来编写此命令。
  2. 读取 4 个字节后,调用ReadFile以读取消息的 rest(具有已知长度)而不指定OVERLAPPED结构。
  3. 命令执行后,例程在阶段 1 继续。并等待下一个命令。

当我阅读文档时

重叠操作需要一个名为 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_BLOCKZwReadFile 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM