Я связываюсь между двумя процессами на разных машинах через канал, используя процедуры завершения ввода-вывода.
Иногда, когда вызывается подпрограмма завершения для WriteFileEx, параметр подпрограммы завершения dwErrorCode равен 0 (т. Е. Без ошибок), GetOverlappedResult возвращает true (т. Е. Без ошибок), но dwNumberOfBytesTransfered не соответствует nNumberOfBytesToWrite в вызове WriteFileEx. Однако я вижу это только на стороне клиента.
Если количество переданных байтов не соответствует количеству байтов, которое было запрошено для передачи, как это можно считать успешным?
Вот как создается дескриптор клиента для канала:
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];
РЕДАКТИРОВАТЬ:
После попытки заново инициализировать перекрывающуюся структуру, как предложил Гарри, я заметил нечто странное.
я memset
OVERLAPPED
структура к нулю перед каждым WriteFileEx
и примерно 1/5000 стандартных обратных вызовов, cbWritten
параметр и OVERLAPPED
структура-х InternalHigh
элемент member теперь был настроен на размер предыдущего сообщения вместо самого последнего сообщения. Я добавил некоторые записи в файл как на клиентском, так и на серверном концах канала внутри подпрограмм завершения, и данные, отправленные и полученные на обоих концах, имели точное совпадение (и правильные, ожидаемые данные). Это тогда показало, что за время, необходимое для записи данных в файл, InternalHigh
член в OVERLAPPED
структура изменилась и теперь отражает размер ожидаемого сообщения (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 бит.
Эта страница MSDN говорит:
«Система не использует структуру OVERLAPPED после вызова процедуры завершения, поэтому процедура завершения может освободить память, используемую перекрытой структурой».
…так очевидно, что этот код может воспроизвести никогда не должно произойти?
Это ошибка WINAPI?
добавленной FILE_FLAG_NO_BUFFERING
к CreateFile
позвоните — не видел проблемы с тех пор. Спасибо всем, кто прокомментировал ваше время.
Других решений пока нет …