簡體   English   中英

打破 ReadFile() 阻塞 - 命名管道 (Windows API)

[英]Breaking ReadFile() blocking - Named Pipe (Windows API)

為簡化起見,這是一種 NamedPipe SERVER 正在等待 NamedPipe CLIENT 寫入管道的情況(使用 WriteFile())

阻塞的 Windows API 是 ReadFile()

服務器已創建啟用阻塞的同步管道(無重疊 I/O)

客戶端已連接,現在服務器正在等待一些數據。

在正常的事物流中,客戶端發送一些數據,服務器處理它,然后返回 ReadFile() 等待下一個數據塊。

同時發生一個事件(例如用戶輸入),NamedPipe SERVER 現在必須執行一些其他代碼,而 ReadFile() 阻塞時它無法執行此操作。

在這一點上我需要提到 NamedPipe Client 不是我的應用程序,所以我無法控制它。 我不能讓它發送幾個字節來解鎖服務器。 它只是坐在那里不發送數據。 由於我無法控制客戶端實現,因此我無法更改任何內容。

一種解決方案是創建一個單獨的線程,在其中執行所有 ReadFile() 操作。 這樣當事件發生時,我可以只處理代碼。 問題是該事件還需要一個單獨的線程,所以現在我為該服務器的每個實例都有兩個額外的線程。 由於這需要可擴展,因此這是不可取的。

從另一個線程我嘗試調用

 DisconnectNamedPipe()

 CloseHandle()

它們都不會返回(直到客戶端寫入管道。)

我無法連接到同一個管道並寫入幾個字節,因為:

“命名管道的所有實例共享相同的管道名稱,但每個實例都有自己的緩沖區和句柄,並為客戶端/服務器通信提供單獨的管道。”

http://msdn.microsoft.com/en-us/library/aa365590.aspx

我需要一種方法來偽造它,所以 64,000 美元的問題是:

如何打破 ReadFile() 的阻塞?

在 ReadFile 之前試試這個:

BOOL WINAPI PeekNamedPipe(
  __in       HANDLE hNamedPipe,
  __out_opt  LPVOID lpBuffer,
  __in       DWORD nBufferSize,
  __out_opt  LPDWORD lpBytesRead,
  __out_opt  LPDWORD lpTotalBytesAvail,
  __out_opt  LPDWORD lpBytesLeftThisMessage
);

if(TotalBytesAvail > 0)
  ReadFile(....);

-AV-

看看 CancelSynchronousIo

將指定線程發出的掛起同步 I/O 操作標記為已取消。

和 CancelIo/CancelIoEx:

要取消所有掛起的異步 I/O 操作,請使用:

CancelIo — 此函數僅取消調用線程為指定文件句柄發出的操作。

CancelIoEx — 此函數取消指定文件句柄的線程發出的所有操作。

麥克風,

您不能取消同步 ReadFile。 但是您可以切換到異步(重疊)操作。 通過這樣做,您可以實現一個非常可擴展的架構。

可能的算法(只是一個想法):

  • 對於每個新客戶端調用 ReadFile
  • 句柄重疊的 WaitForMultipleObjects.hEvent + 您的自定義事件
  • 迭代信號事件,並安排它們由線程池中的線程執行。

這樣你就可以只有很少的線程來接收連接和讀取數據,而實際的數據處理可以由線程池完成。

問題是該事件還需要一個單獨的線程,所以現在我為該服務器的每個實例都有兩個額外的線程。 由於這需要可擴展,因此這是不可取的。

在我的職業生涯中,我從未發現“更多線程”==“可擴展性較差”。 你有多少這樣的“服務器”實例?

通常,如果該操作將被阻塞並且系統需要在該操作被阻塞時做出響應,則該操作需要在單獨的線程中執行。

發生的事情是當您的客戶端嘗試連接到服務器入站管道(不再存在)時,服務器出站管道處於打開狀態等待連接......您需要做的是沖洗出站管道以便循環回到您的入站。 您可以通過讀取文件在客戶端刷新(記住循環連接建立,因為那里有“握手”,它永遠不會第一次工作)

如果異步 I/O 操作使用 I/O 完成端口,則不必阻塞任何線程。 請參閱: http : //msdn.microsoft.com/en-us/library/aa365198(VS.85).aspx

只需使用SetNamedPipeHandleState函數https://docs.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-setnamedpipehandlestate

調用此函數時使用PIPE_NOWAIT標志。

hNamedPipe應該是從CreateFile函數返回的句柄。

之后,當沒有可用數據時,對ReadFile的調用將不會阻塞線程。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM