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如此,如何正确地做到这一点?

4

6 回答 6

4

恕我直言,这种在实际写入之前检查可用空间的方法是有缺陷的。

可能会发生这样的情况,在执行实际写入时,并行运行的其他一些进程会填满可用磁盘空间的最后一位,从而导致您的 WriteFile 失败。

我只会依赖 WriteFile 返回的内容。

于 2010-09-15T13:12:23.373 回答
2

lpTotalBytesAvail参数中返回的值是可以从管道读取的字节数,而不是写入管道的字节数。为您提供信息以分配从管道读取数据的缓冲区。

写入管道或任何 NT Krenel 句柄时处理错误的正确方法是简单地执行对WriteFile()的调用并处理返回的任何错误。

检查然后写入模式无效,并且会产生错误 * 在您的测试中永远不会发生 * 有时会在现场发生 * ...因此很难诊断和调试 * 最重要的是,这些错误会惹恼您的用户。

原因是目标的状态可以在检查和实际写入之间发生变化。这意味着调用 WriteFile() 的代码无论如何都必须检查错误。这意味着在调用 WriteFile() 之前检查前置条件只是额外的代码,没有提供任何价值。

这种模式无效的原因是 Windows(和所有其他操作系统 - 这不仅仅是 Windows 的东西) - 不能将“检查”和“写入”视为原子操作。底层操作系统是完全异步的,并且通话之间可能会发生很多事情。

因此,如果您简单地调用 WriteFile() 并做好错误处理,您的代码将会更简单、更可靠。

-Foredecker

于 2010-09-19T14:22:01.630 回答
1

Set PIPE_NOWAIT instead of PIPE_WAIT. Then WriteFile will return immediately if there's not enough room in the pipe.
And 100 seems rather small for the I/O buffer sizes! What is your pipe for?

于 2010-09-20T12:18:22.420 回答
1

关于 check then write 的脆弱性的评论是正确的。

Microsoft 不推荐 PIPE_NOWAIT 的建议。

使用重叠 I/O。然后 WriteFile() 将始终立即返回,如果数据没有立即写入管道,将返回 FALSE 和 ERROR_IO_PENDING。在这种情况下,您调用 CancelIo() 来取消尝试的 WriteFile()。请记住,在调用 CancelIo() 之后,您必须调用 GetOverlappedResult(),因为重叠的 WriteFile() 仍然需要完成 - 即使它会失败并且如果在它之前释放 OVERLAPPED 结构,您将有堆栈损坏。

顺便说一句,你应该接受这个问题的答案。你问它已经一年多了!

于 2011-10-10T15:48:48.873 回答
1

您无法以您的方式确定可用空间。

虽然这个问题是关于管道的,但人们可能会在寻找有关发现可用磁盘空间的一般信息时遇到它,如果管道最终是一个文件,这可能仍然有用:

知识库文章“了解和使用 GetDiskFreeSpace 和 GetDiskFreeSpaceEx”提供了有关确定可用磁盘空间的相关 Win32 API 的信息,或直接转到此处的 API 文档:

于 2010-09-14T07:13:04.537 回答
0

创建一个线程来处理写入管道,这样写入器挂起,等待客户端清空管道不是问题吗?

于 2010-09-21T01:56:43.167 回答