WSARecv иногда возвращает "неверный дескриптор (ошибка № 6)" для сокета, связанного с портом IOCP. (C++)

Я пытаюсь написать сервер, который может поддерживать множество клиентских подключений одновременно, поэтому я пытаюсь сделать это с 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".

1 ответ

Решение

Я контролировал все системные вызовы, которые происходили в фоновом режиме. WSARecv внутренне вызывает NtDeviceIoControlFile, и существует аргумент "Событие", который совпадает с тем, что передается в структуре lpOverlapped WSARecv как hEvent. Я не устанавливал hEvent в NULL, поэтому он принимал какое-то мусорное значение, когда он был NULL, тогда NtDeviceIoControlFile возвращался успешно, а для других случаев он возвращал ошибку "INVALID_HANDLE". К сожалению, большую часть времени это было NULL.

Другие вопросы по тегам