簡體   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