WriteFileEx完成例程成功,但传输的字节不正确
WriteFileEx completion routine succeeds, but bytes transferred is incorrect
我使用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];
编辑:
按照哈利的建议,在尝试重新初始化重叠的结构后,我注意到了一些奇怪的东西。在每个WriteFileEx
和大约1/5000完成例程回调之前,memset
将OVERLAPPED
结构设置为零,cbWritten
参数和OVERLAPPED
结构的InternalHigh
成员现在被设置为前一消息的大小,而不是最近消息的大小。我在完成例程内的管道的客户端和服务器端的文件中添加了一些日志记录,并且在两端发送和接收的数据完全匹配(以及正确的预期数据)。这表明,在将数据写入文件所需的时间内,OVERLAPPED
结构中的InternalHigh
成员已经更改,现在反映了我预期的消息大小(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);
来完成在Windows7 64位上调用的例程。
这个MSDN页面上写着:
"调用完成例程后,系统不使用OVERLAPPED结构,因此完成例程可以解除分配重叠结构使用的内存。">
。。。显然,这个代码所能复制的东西永远不会发生?
这是WINAPI错误吗?
将FILE_FLAG_NO_BUFFERING
添加到CreateFile
调用中-此后再也没有发现问题。感谢所有评论您的时间。
- 如何使用CAPL的诊断功能获取CAN传输的数据(256字节)?
- 如何从 Oracle 数据库中获取 qt 中 SQL 查询的传输字节大小?
- 传输文件一次又一次地发送相同的字节
- 我想将四个字节合并为一个数字以进行串行传输
- 如何在C++中将整数转换为字节,以便 Unity 在通过 UDP 传输后能够理解它们
- 提升::Asio 使用异步操作时传输的字节
- 如何将字节从 std::ostream 流式传输到 std::vector<uint8_t>?
- 如何封装两个容器之间的传输字节
- WriteFileEx完成例程成功,但传输的字节不正确
- 将 cv::Mat 存储在字节数组中,以便将数据传输到服务器
- Winsock send() 单字节传输的问题
- 如何获取通过 libcurl 连接传输的总字节数
- 从比特集读取比特值并传输到字节数组
- 将文件从客户端传输到服务器时缺少字节,字节值也表示一些控制字符
- JNI-从jstring到字节的传输,从字节到字符串的传输问题
- 转换之间的双和字节数组,为传输ZigBee API
- 我怎样才能得到异步读取上传输的字节量
- 通过boost::asio传输混合unicode和单字节字符的最佳方式
- 用于数据传输的标准字节通信协议
- UDP 传输和维护网络字节顺序