[英]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。 但是您可以切換到異步(重疊)操作。 通過這樣做,您可以實現一個非常可擴展的架構。
可能的算法(只是一個想法):
這樣你就可以只有很少的線程來接收連接和讀取數據,而實際的數據處理可以由線程池完成。
問題是該事件還需要一個單獨的線程,所以現在我為該服務器的每個實例都有兩個額外的線程。 由於這需要可擴展,因此這是不可取的。
在我的職業生涯中,我從未發現“更多線程”==“可擴展性較差”。 你有多少這樣的“服務器”實例?
通常,如果該操作將被阻塞並且系統需要在該操作被阻塞時做出響應,則該操作需要在單獨的線程中執行。
發生的事情是當您的客戶端嘗試連接到服務器入站管道(不再存在)時,服務器出站管道處於打開狀態等待連接......您需要做的是沖洗出站管道以便循環回到您的入站。 您可以通過讀取文件在客戶端刷新(記住循環連接建立,因為那里有“握手”,它永遠不會第一次工作)
如果異步 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.