我正在使用IO完成例程通过管道在不同机器上的两个进程之间进行通信。
有时,当调用WriteFileEx的完成例程时,完成例程参数dwErrorCode为0(即无错误),GetOverlappedResult返回true(即无错误),但dwNumberOfBytesTransfered与对WriteFileEx的调用中的nNumberOfBytesToWrite不匹配。但是,我仅在管道的客户端上看到此内容。
如果传输的字节数与请求传输的字节数不匹配,那么如何将其视为成功?
这是创建客户端对管道的句柄的方式:
mHPipe = CreateFile(pipeName, // pipe name
GENERIC_READ | // read and write access
GENERIC_WRITE,
0, // no sharing
NULL, // default security attributes
OPEN_EXISTING, // opens existing pipe
FILE_FLAG_OVERLAPPED | // overlapped
FILE_FLAG_WRITE_THROUGH, // write through mode
NULL); // no template file
// do some checking...
// The pipe connected; change to message-read mode.
DWORD dwMode = PIPE_READMODE_MESSAGE;
BOOL fSuccess = SetNamedPipeHandleState(mHPipe, // pipe handle
&dwMode, // new pipe mode
NULL, // don't set maximum bytes
NULL); // don't set maximum time
谁能看到为什么会这样?
谢谢
编辑:
相关的WriteFileEx代码如下:
void WINAPI CompletedWriteRoutine(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverLap)
{
BOOL fWrite = FALSE;
LPPIPEINST lpPipeInst = (LPPIPEINST)lpOverLap;
//
// ! 99.9% of the time, dwNumberOfBytesTransfered == lpPipeInst->cbDataSize
// but 0.1% of the time, they do not match
//
// Some stuff
// Copy next message to send
memcpy_s(lpPipeInst->chData, sizeof(lpPipeInst->chData), pMsg->msg, pMsg->size);
lpPipeInst->cbDataSize = pMsg->size;
// Some other stuff
fWrite = WriteFileEx(lpPipeInst->hPipeInst,
lpPipeInst->chData,
lpPipeInst->cbDataSize,
(LPOVERLAPPED) lpPipeInst,
(LPOVERLAPPED_COMPLETION_ROUTINE)CompletedWriteRoutine);
// Some other, other stuff
}
LPPIPEINST声明为:
typedef struct
{
OVERLAPPED oOverlap; // must remain first item
HANDLE hPipeInst;
TCHAR chData[BUFSIZE];
DWORD cbDataSize;
} PIPEINST, *LPPIPEINST;
并且对CompletedWriteRoutine的初始调用具有由此声明的lpOverlap参数:
PIPEINST pipeInstWrite = {0};
pipeInstWrite.hPipeInst = client.getPipeHandle();
pipeInstWrite.oOverlap.hEvent = hEvent[eventWriteComplete];
编辑:
在尝试按照Harry的建议重新初始化重叠的结构后,我注意到了一些奇怪的东西。
我在每个
memset
之前将OVERLAPPED
结构WriteFileEx
设置为零,并进行大约1/5000完成例程回调,现在将cbWritten
参数和OVERLAPPED
结构的InternalHigh
成员设置为上一条消息的大小,而不是最新消息的大小。我在完成例程中的管道的客户端和服务器端都添加了一些日志记录,并且在两端发送和接收的数据完全匹配(以及正确的预期数据)。然后,这表明在将数据写入文件所花费的时间中,InternalHigh
结构中的OVERLAPPED
成员已更改为现在可以反射(reflect)我期望的消息大小(cbWritten
仍然是旧消息大小)。我删除了文件日志记录,现在可以使用以下代码重现该问题,例如发条:void WINAPI CompletedWriteRoutine(DWORD dwErr, DWORD cbWritten, LPOVERLAPPED lpOverLap)
{
LPPIPEINST lpPipeInst = (LPPIPEINST)lpOverLap;
// Completion routine says it wrote the amount of data from the previous callback
if (cbWritten != lpPipeInst->cbDataSize)
{
// Roughly 1 in 5000 callbacks ends up in here
OVERLAPPED ovl1 = lpPipeInst->oOverlap; // Contains size of previous message, i.e. cbWritten
Sleep(100);
OVERLAPPED ovl2 = lpPipeInst->oOverlap; // Contains size of most recent message, i.e lpPipeInst->cbDataSize
}
...
}
似乎有时在
OVERLAPPED
结构和完成例程输入参数更新之前调用完成例程。我正在使用MsgWaitForMultipleObjectsEx(eventLast, hEvent, INFINITE, QS_POSTMESSAGE, MWMO_ALERTABLE);
作为要在Windows 7 64位上调用的完成例程。This MSDN page说:
...如此显然,此代码可以复制的内容永远不会发生?
这是WINAPI错误吗?
最佳答案
在FILE_FLAG_NO_BUFFERING
调用中添加了CreateFile
-此后未发现问题。感谢所有为您的时间发表评论的人。