PeekNamedPipe 在给定来自服务器的句柄时无法给出正确的可用字节数,仅当句柄来自客户端时才有效

PeekNamedPipe cannot give correct number of bytes available when given a Handle from the server, only works when the Handle come from the client

PeekNamedPipe 函数文档说 Handle 参数可以来自服务器端 (CreateNamedPipe) 或客户端 (CreateFile)。

hNamedPipe [in] A handle to the pipe. This parameter can be a handle to a named pipe instance, as returned by the CreateNamedPipe or CreateFile function, or it can be a handle to the read end of an anonymous pipe, as returned by the CreatePipe function. The handle must have GENERIC_READ access to the pipe.

当我给函数一个来自 CreateNamedPipe 的句柄时,无论管道实际包含什么,我总是得到 0 作为可用字节数。

以下代码有效:

#include <iostream>
#include <windows.h>
using namespace std;

int main(int argc, const char **argv)
{
    wcout << "Creating an instance of a named pipe..." << endl;

    // Create a pipe to send data
    HANDLE pS = CreateNamedPipe(L"\\.\pipe\my_pipe", PIPE_ACCESS_DUPLEX, 0, 1, 100, 100, 0, NULL);

    // Open the named pipe
    HANDLE pC = CreateFile(L"\\.\pipe\my_pipe", GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

    if (pC == INVALID_HANDLE_VALUE)
    {
        wcout << "Failed to connect to pipe." << endl;
        return 1;
    }

    wcout << "Test PeekNamedPipe #1." << endl;
    DWORD PipeByteNum = 0;
    BOOL res = PeekNamedPipe(pC, NULL, 0, NULL, &PipeByteNum, NULL);
    if(!res)
    {
          wcout << "PeekNamedPipe() - failed." << endl;
          return 1;
    }
    wcout << " - Number of bytes in pipe: " << PipeByteNum << endl << endl;

    wcout << "Sending data to pipe..." << endl;

   const wchar_t *data = L"Hello Pipe World";
   DWORD numBytesWritten = 0;
   BOOL result = WriteFile(pS, data, wcslen(data) * sizeof(wchar_t), &numBytesWritten, NULL);

    if (result)
      wcout << "Number of bytes sent: " << numBytesWritten << endl;
    else
    {
      wcout << "Failed to send data." << endl;
      return 1;
    }

    wcout << "Test PeekNamedPipe #2." << endl;
    PipeByteNum = 0;
    res = PeekNamedPipe(pC, NULL, 0, NULL, &PipeByteNum, NULL);
    if(!res)
    {
          wcout << "PeekNamedPipe() - failed." << endl;
          return 1;
    }
    wcout << " - Number of bytes in pipe: " << PipeByteNum << endl << endl;

    wcout << "Reading data from pipe..." << endl;

    // The read operation will block until there is data to read
    wchar_t buffer[128];
    DWORD numBytesRead = 0;
    result = ReadFile(pC, buffer, 5 * sizeof(wchar_t), &numBytesRead, NULL);

    if (result)
    {
      buffer[numBytesRead / sizeof(wchar_t)] = '[=10=]'; // null terminate the string
      wcout << "Number of bytes read: " << numBytesRead << endl;
      wcout << "Message: " << buffer << endl;
    }
    else
    {
      wcout << "Failed to read data from the pipe." << endl;
      return 1;
    }

    wcout << "Test PeekNamedPipe #3." << endl;
    PipeByteNum = 0;
    res = PeekNamedPipe(pC, NULL, 0, NULL, &PipeByteNum, NULL);
    if(!res)
    {
          wcout << "PeekNamedPipe() - failed." << endl;
          return 1;
    }
    wcout << " - Number of bytes in pipe: " << PipeByteNum << endl << endl;

    // Close client.
    CloseHandle(pC);
    wcout << "Done with client." << endl;

    // Close the pipe.
    CloseHandle(pS);
    wcout << "Done with server." << endl;

    return 0;
}

输出是:

Creating an instance of a named pipe...
Test PeekNamedPipe #1.
 - Number of bytes in pipe: 0

Sending data to pipe...
Number of bytes sent: 32
Test PeekNamedPipe #2.
 - Number of bytes in pipe: 32

Reading data from pipe...
Number of bytes read: 10
Message: Hello
Test PeekNamedPipe #3.
 - Number of bytes in pipe: 22

Done with client.
Done with server.

现在,如果我将 pS(服务器句柄)而不是 pC(客户端句柄)提供给 PeekNamedPipe,则可用字节数始终为 0。

输出变为:

Creating an instance of a named pipe...
Test PeekNamedPipe #1.
 - Number of bytes in pipe: 0

Sending data to pipe...
Number of bytes sent: 32
Test PeekNamedPipe #2.
 - Number of bytes in pipe: 0

Reading data from pipe...
Number of bytes read: 10
Message: Hello
Test PeekNamedPipe #3.
 - Number of bytes in pipe: 0

Done with client.
Done with server.

来自documentation for PeekNamedPipe,右上角的备注:

The PeekNamedPipe function is similar to the ReadFile function

您不能使用 ReadFile 读取您发送到管道另一端的数据,因此您不能使用 PeekNamedPipe 获取有关您发送到管道另一端的数据的信息要么。

如果您想知道管道另一端的进程读取了多少传出数据,您需要在数据协议中构建某种反馈。