Я использую IOCP на Windows. Ранее я использовал метод GetQueuedCompletionStatus
опросить очередь и все было хорошо. Но когда я решил реорганизовать логику таким образом, чтобы использовать процедуру завершения с WSARecv
вызвать это всегда терпит неудачу с ошибкой WSAEINVAL
(10022). Этот код в потоке создан с CreateTread
int flags = 0;
m_iocport = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 0);
handle = CreateIoCompletionPort(clientSocket, m_iocport, 0, 0);
OVERLAPPED_EX *over = new OVERLAPPED_EX();
result = WSARecv(clientSocket, &over->m_wsabuf, 1, NULL, &flags, over, WorkerRoutine);
А рабочая подпрограмма пуста и имеет следующее определение:
void static CALLBACK WorkerRoutine(DWORD Error, DWORD BytesTransferred, LPWSAOVERLAPPED Overlapped, DWORD InFlags) {}
Когда я прохожу NULL
вместо WorkerRoutine
к методу WSARecv все работает нормально. Но когда я передаю процедуру завершения вызова, она завершается с ошибкой 10022. Я пытался использовать WorkerRoutine
а также &WorkerRoutine
ничего не помогает
hEvent
свойство установлено в NULL в объекте OVERLAPPED_EX.
порт завершения ввода / вывода, связанный с файлом и lpCompletionRoutine
это взаимоисключающие параметры. Вы не можете использовать его одновременно. когда вы делаете это — ядро возвращает STATUS_INVALID_PARAMETER
который переводится на WSAEINVAL
, так ты и должен получить именно эту ошибку.
IOCP и ApcRoutine 2 разными способами уведомляют вас о завершении операции. при использовании IOCP — система отправляет пакет в IOCP по завершении. вам нужно использовать GetQueuedCompletionStatus
или же NtRemoveIoCompletion
извлечь этот пакет позже. и это не «опрос». с другой стороны, если вы используете ApcRoutine
Системная вставка apc в вашу ветку. использовать два способа уведомления одновременно и одновременно — это логическая ошибка и правильное выполнение ядра при возврате к вам STATUS_INVALID_PARAMETER
в этом случае.
к сожалению, это не ясно указано в MSDN или как минимум, я не могу найти это. но некоторые исследования + исходный код WRK помогают понять эту ситуацию:
WSARecv
внутренний звонок ZwDeviceIoControlFile
и как результат в ядре называется IopXxxControlFile
. когда lpCompletionRoutine != 0
ApcRoutine
параметр для IopXxxControlFile
присутствует, и вы терпите неудачу именно в этот пункт:
//
// If this file has an I/O completion port associated w/it, then ensure
// that the caller did not supply an APC routine, as the two are mutually
// exclusive methods for I/O completion notification.
//
if (fileObject->CompletionContext && IopApcRoutinePresent( ApcRoutine )) {
ObDereferenceObject( fileObject );
return STATUS_INVALID_PARAMETER;
}
также вы можете разместить m_wsabuf в стеке. допустимым должен быть только буфер до какой точки WSABUF
Если эта функция выполняется в наложенном виде, это
Обязанность поставщика услуг Winsock захватить WSABUF
структуры, прежде чем вернуться из этого вызова. Это позволяет приложениям
строить на основе стека WSABUF массивы, на которые указывает lpBuffers
параметр.
так что вы можете разместить OVERLAPPED_EX
единственный буфер до какой точки WSABUF.buf
но не целый WSABUF
, но это уже не связано с вашей ошибкой
Других решений пока нет …