2010-09-11 66 views
3
hPipe = CreateNamedPipe( 
    lpszPipename,    // pipe name 
    PIPE_ACCESS_DUPLEX,  // read/write access 
    PIPE_TYPE_MESSAGE |  // message type pipe 
    PIPE_READMODE_MESSAGE | // message-read mode 
    PIPE_WAIT,    // blocking mode 
    PIPE_UNLIMITED_INSTANCES, // max. instances 
    100,     // output buffer size 
    100,     // input buffer size 
    0,      // client time-out 
    NULL);     // default security attribute 

    DWORD totalBytesAvailable; 
    PeekNamedPipe( 
    hPipe ,    // __in  HANDLE hNamedPipe, 
    NULL,     // __out_opt LPVOID lpBuffer, 
    0,      // __in  DWORD nBufferSize, 
    NULL,     // __out_opt LPDWORD lpBytesRead, 
    &totalBytesAvailable, // __out_opt LPDWORD lpTotalBytesAvail, 
    NULL     // __out_opt LPDWORD lpBytesLeftThisMessage 
); 
    if(totalBytesAvailable allows) 
    WriteFile(tmp_pipe, pBuffer, BufferLen, &dwWritten, NULL); 

正如你看到我用PeekNamedPipe來獲得可用空間,但事實證明,totalBytesAvailable總是0,如何正確地做到這一點?如何檢查窗口中c在WriteFile之前是否有足夠的空間?

+0

修復了複製粘貼問題。 – Alan 2010-09-11 06:51:29

+0

@Frerich - 當然,我在SO上度過的時光。它知道這對艾倫沒有任何價值,但我當然在乎。考慮到它的價格,懶惰的答案是愚蠢的。 – 2010-09-15 13:43:58

+0

我想你寫信給'hPipe',而不是一些未知的'tmp_pipe'? – pascal 2010-09-21 01:47:54

回答

2

您無法以自己的方式確定可用空間。

雖然這個問題是關於管道,這是可能的人可能會遇到它找的一般信息,發現可用的磁盤空間,如果管道是最終文件,這仍然可能是有用的:

的知識庫文章"Understanding and Using GetDiskFreeSpace and GetDiskFreeSpaceEx"會給出相關的Win32 API信息用於確定可用磁盤空間,或者直接去API文檔在這裏:

+0

-1,pipe!= disk。 – MSalters 2010-09-14 07:32:20

+0

我意識到,會編輯澄清。這個問題的表述方式很可能會導致正在尋找一種方法來尋找可用磁盤空間的人,所以我認爲它仍然有用。 – 2010-09-14 07:35:58

4

恕我直言,這種在做實際寫入之前檢查可用空間的方法是有缺陷的。

可能發生的情況是,實際寫入執行時,其他一些並行運行的進程會填滿可用磁盤空間的最後幾位,從而導致WriteFile失敗。

我只會依賴WriteFile返回的內容。

+0

我不能依賴'WriteFile',它會掛起!在我的情況下,不需要擔心多線程的情況。 – Alan 2010-09-16 14:42:44

+0

沒有這是做到這一點的正確方法。其他進程共享磁盤,但不能保證它們不會填滿您推定要求的空閒空間。如果發生錯誤(例如沒有磁盤空間),調用將不會掛起。在調用之後,你應該得到類似'GetLastError()== ERROR_DISK_FULL'的東西。 – 2010-09-18 15:15:31

+0

如果沒有剩餘空間用於WriteFile,我將避免該調用。 – wamp 2010-09-20 08:15:28

2

lpTotalBytesAvail參數返回的值是從一個管道,不寫入到管道讀可能的字節數。爲您提供從管道分配緩衝區讀數據的信息。

在寫入管道或任何NT Krenel句柄時處理錯誤的正確方法是簡單地執行對WriteFile()的調用並處理返回的任何錯誤。

支票然後寫模式不是有效的,會產生錯誤的是 *不要在你的測試 發生*在現場 * ......時有發生,因此是非常難以診斷和調試 *最重要的是,這樣的錯誤會惹惱你的用戶。

原因是目標的狀態可能會在檢查和實際寫入之間發生變化。這意味着調用WriteFile()的代碼必須檢查錯誤。這意味着在調用WriteFile()之前檢查一個前置條件是簡單的額外代碼,它不提供任何值。

該模式不起作用的原因是Windows(以及所有其他操作系統 - 這不僅僅是一個Windows事物)不能將「檢查」和「寫入」視爲原子操作。是完全異步和大量的可調用之間發生。

所以,你的代碼會更簡單更reliabile如果你簡單的調用的WriteFile()和做的錯誤處理好工作。

-Foredecker

+0

沒有錯誤,只是掛起,我要避免。 – wamp 2010-09-20 08:06:27

1

集PIPE_NOWAIT代替PIPE_WAIT。如果管道中沒有足夠的空間,則WriteFile將立即返回。
對於I/O緩衝區大小,100似乎相當小!你的管道是什麼?

+0

PIPE_NOWAIT將會立即返回... – pascal 2010-09-21 01:55:28

+0

這就是我所說的,不是嗎? – TonyK 2010-09-21 11:19:52

+0

然後你就不會知道'WriteFile'是否成功。 – Alan 2010-09-21 15:09:58

0

創建一個線程來處理寫入管道,以便寫入器掛起時不會出現問題,等待客戶端清空管道?

0

關於檢查然後寫入的脆弱性的評論是正確的。

Microsoft建議不建議使用PIPE_NOWAIT。

使用重疊的I/O。然後WriteFile()將總是立即返回,並且如果數據沒有立即寫入管道,將返回FALSE和ERROR_IO_PENDING。在這種情況下,您可以調用CancelIo()來取消嘗試的WriteFile()。請記住,在調用CancelIo()之後,必須調用GetOverlappedResult(),因爲重疊的WriteFile()仍然需要完成 - 即使它將會失敗,並且如果在釋放之前釋放了OVERLAPPED結構,將會導致堆棧損壞。

順便說一句,你應該接受關於這個問題的答案。這是你問了一年多了!

相關問題