11

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

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

我看过 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
);

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

4

2 回答 2

6

为什么你认为你不能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
}
于 2012-09-22T11:47:20.753 回答
1

好吧,您正在使用 ReadFile()。该文件说,除其他外:

如果在消息模式下读取命名管道并且下一条消息比 nNumberOfBytesToRead 参数指定的长,ReadFile 返回 FALSE,GetLastError 返回 ERROR_MORE_DATA。可以通过对 ReadFile 或 PeekNamedPipe 函数的后续调用来读取消息的其余部分。

你试过吗?我从来没有使用过这样的管道:-),只用它们来访问子进程的标准输入/输出句柄。

我假设可以根据需要经常重复上述内容,从而使“消息的剩余部分”的描述有些不准确:我认为如果“剩余部分”不适合您的缓冲区,您只会得到另一个 ERROR_MORE_DATA 所以你知道得到剩余的剩余部分。

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

于 2012-09-22T10:50:19.007 回答