命名管道,如何知道读取端读取的确切字节数。 C ++,Windows

时间:2012-09-22 10:44:01

标签: c++ named-pipes

我使用命名管道配置为将数据作为单字节流发送,以在两个应用程序之间发送序列化数据结构。序列化数据的大小变化非常大。在发送方面,这不是问题,我可以调整要发送的字节数。

如何将接收(读取)端的缓冲区设置为要读取的确切字节数?有没有办法知道发送(写入)方面的数据有多大?

我看过PeekNamedPipe,但这个函数对于字节类型的命名管道似乎没用了吗?

  

lpBytesLeftThisMessage [out,optional]   指向变量的指针,该变量接收此消息中剩余的字节数。对于字节类型的命名管道或匿名管道,此参数将为零。如果不读取数据,则此参数可以为NULL。

http://msdn.microsoft.com/en-us/library/windows/desktop/aa365779(v=vs.85).aspx

如果无法确定所需的缓冲区大小,如何最好地处理这种情况?

发送代码

    string strData;
strData =  "ShortLittleString";

DWORD numBytesWritten = 0;
result = WriteFile(
    pipe, // handle to our outbound pipe
    strData.c_str(), // data to send
    strData.length(), // length of data to send (bytes)
    &numBytesWritten, // will store actual amount of data sent
    NULL // not using overlapped IO
);

阅读代码:

DWORD numBytesToRead0 = 0;
DWORD numBytesToRead1 = 0;
DWORD numBytesToRead2 = 0;

BOOL result = PeekNamedPipe(
pipe,
NULL,
42,
&numBytesToRead0,
&numBytesToRead1,
&numBytesToRead2
);

char * buffer ;

buffer = new char[numBytesToRead2];

char data[1024]; //1024 is way too big and numBytesToRead2 is always 0 
DWORD _numBytesRead = 0;

BOOL    result = ReadFile(
pipe,
data, // the data from the pipe will be put here
1024, // number of bytes allocated
&_numBytesRead, // this will store number of bytes actually read
NULL // not using overlapped IO
);

在上面的代码中, buffer 总是大小为0,因为PeakNamedPipe函数为所有 numBytesToRead 变量返回0。有没有办法准确设置此缓冲区大小?如果没有,处理这种情况的最佳方法是什么?谢谢你的帮助!

2 个答案:

答案 0 :(得分:3)

为什么您认为无法使用lpTotalBytesAvail来获取已发送的数据大小?它总是在字节模式下适用于我。如果它总是为零可能你做错了什么。还建议使用std::vector作为数据缓冲区,它比使用原始指针和new语句更安全。

  

lpTotalBytesAvail [out, optional]指向变量的指针,该变量接收可从管道读取的总字节数。如果不读取数据,则此参数可以为NULL。

示例代码:

// Get data size available from pipe
DWORD bytesAvail = 0;
BOOL isOK = PeekNamedPipe(hPipe, NULL, 0, NULL, &bytesAvail, NULL);
if(!isOK)
{
   // Check GetLastError() code
}

// Allocate buffer and peek data from pipe
DWORD bytesRead = 0;    
std::vector<char> buffer(bytesAvail);
isOK = PeekNamedPipe(hPipe, &buffer[0], bytesAvail, &bytesRead, NULL, NULL);
if(!isOK)
{
   // Check GetLastError() code
}

答案 1 :(得分:1)

好吧,你正在使用ReadFile()。文档说,除其他外:

  

如果正在以消息模式读取命名管道并且下一条消息更长   比nNumberOfBytesToRead参数指定的,ReadFile返回FALSE和   GetLastError返回ERROR_MORE_DATA。可以读取消息的其余部分   随后调用ReadFile或PeekNamedPipefunction。

你试过那个吗?我从来没有使用像这样的管道:-),只用它们来到子进程的stdin / out句柄。

我假设上面的内容可以根据需要重复进行,使“消息的剩余部分”描述得有点不准确:我认为如果“余数”不适合你的缓冲区你就会得到另一个ERROR_MORE_DATA让你知道剩余的余数。

或者,如果我完全误解了你,你实际上并没有使用这种“消息模式”的东西:也许你只是以错误的方式阅读。您可以使用固定大小的缓冲区将数据读入并将其附加到最终块,直到您到达数据末尾。或者通过增加“固定”大小缓冲区的大小来优化这一点。