2010-09-11 69 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结构,将会导致堆栈损坏。

顺便说一句,你应该接受关于这个问题的答案。这是你问了一年多了!

相关问题