Я пытаюсь написать сервер, который может поддерживать множество клиентских подключений одновременно, поэтому я пытаюсь сделать это с IOCP. Итак, позвольте мне кратко рассказать о моем потоке кода, и тогда я смогу объяснить свою проблему. Прежде всего, сервер открывает порт для прослушивания и ожидания вызова «принять» для новых входящих соединений. Для справки я использовал тот же код, что и упомянутый Вот Таким образом, он принимает каждое новое входящее соединение и возвращает новый дескриптор сокета (sd), а затем помечает как неблокирующий с помощью:
arg = 1;
ioctlsocket(sd, FIONBIO, &arg);
и затем включите TCP_NODELAY:
level = IPPROTO_TCP;
optName = TCP_NODELAY;
value = 1;
setsockopt(sd, level, optName, (const char*)&value, sizeof(value));
после этого связывается с портом IOCP как:
CreateIoCompletionPort((HANDLE)sd, iocp_port, (DWORD)completion_key, 4);
завершение_ключа — это объект класса, который является не чем иным, как контейнером, он содержит буфер данных, буфер перекрытия, тип запроса recv / send и т. д.
и в последнем издании вызов для чтения:
WSARecv(sd, wsabuf, 1, &bytes, &flags, overlapped, NULL);
wsabuf и overlapped являются частью объекта дополнения_ключа.
В 90% случаев он работает нормально, то есть когда есть некоторые входящие данные, доступные на этом сокете, «GetQueuedCompletionStatus» разблокируется и у него есть действительные данные. Но иногда вызов WSARecv возвращается с ошибкой, а GetLastError () возвращает 6, что является ошибкой «неверного дескриптора». Я немного сбит с толку, почему так происходит.
То, как я создаю порт iocp:
iocp_port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
и есть потоки, которые ожидают на «GetQueuedCompletionStatus».
Я отслеживал все системные вызовы, которые происходили в фоновом режиме. WSARecv внутренне вызывает NtDeviceIoControlFile, и существует аргумент «Событие», который совпадает с тем, что передается в структуре lpOverlapped WSARecv как hEvent. Я не устанавливал hEvent в NULL, поэтому он принимал какое-то мусорное значение, когда он был NULL, тогда NtDeviceIoControlFile возвращался успешно, а для других случаев он возвращал ошибку «INVALID_HANDLE». К сожалению, большую часть времени это было NULL.
Других решений пока нет …