IOCP AcceptEx не создает завершение при подключении

В настоящее время я пытаюсь некоторые новые библиотеки (IOCP) для программирования сокетов. И я наткнулся на AcceptEx функциональность для включения асинхронных соединений.

Как сказано в документации:

Функция AcceptEx использует перекрывающийся ввод-вывод, в отличие от функции accept. Если ваше приложение использует AcceptEx, оно может обслуживать большое количество клиентов с относительно небольшим количеством потоков. Как и во всех перекрывающихся функциях Windows, либо события Windows, либо порты завершения могут использоваться в качестве механизма уведомления о завершении.

Но я не получаю никакого завершения, когда клиент соединяется. Однако я получаю завершение, когда клиент отправляет данные ..

Это мой код:

DWORD dwBytes;
GUID GuidAcceptEx = WSAID_ACCEPTEX;
int iResult = WSAIoctl(m_hSocket, SIO_GET_EXTENSION_FUNCTION_POINTER,
&GuidAcceptEx, sizeof (GuidAcceptEx),
&m_lpfnAcceptEx, sizeof (m_lpfnAcceptEx),
&dwBytes, NULL, NULL);

if (iResult == SOCKET_ERROR)
{
CloseSocket();
}

А потом:

WSAOVERLAPPED olOverlap;
memset(&olOverlap, 0, sizeof (olOverlap));
char lpOutputBuf[1024];
int outBufLen = 1024;
DWORD dwBytes;

BOOL bRet = m_lpfnAcceptEx( m_hSocket, hSocket, lpOutputBuf,
outBufLen - ((sizeof (sockaddr_in) + 16) * 2),
sizeof (sockaddr_in) + 16, sizeof (sockaddr_in) + 16,
&dwBytes, &olOverlap);
if ( bRet == FALSE )
{
DWORD dwRet = WSAGetLastError();
if( dwRet != WSA_IO_PENDING )
{
return dwRet;
}
}

Любое предложение о том, что делать, чтобы получить пополнения?

РЕДАКТИРОВАТЬ:
Я связываю hSocket с портом завершения после m_lpfnAcceptEx ()

2

Решение

Во-первых WSAOVERLAPPED и буфер данных, который вы объявляете в стеке выше вашего вызова AcceptEx() не будет существовать, когда произойдет завершение (если вы не звоните GetQueuedCompletionStatus() в той же функции, что было бы немного странно). Вам необходимо их динамически распределять или объединять.

Во-вторых, вы заявляете, что связываете сокет с портом завершения после вызова AcceptEx(), Это неверно. Вы должны сделать эти вещи, прежде чем позвонить AcceptEx(),

  1. Создать сокет с WSA_FLAG_OVERLAPPED задавать.
  2. Свяжите это с адресом, который вы хотите прослушать.
  3. Звоните, слушайте его с желаемым отставанием.
  4. нагрузка AcceptEx() динамически, используя сокет прослушивания и вызов WSAIoctl (не обязательно, и код, который вы показываете, должен работать, но таким образом вы можете быть уверены, что вы получаете прослушивающий сокет от того же базового поставщика winsock и что он поддерживает AcceptEx ().
  5. нагрузка GetAcceptExSockaddrs() так же, как вы загружаете AcceptEx() — он понадобится вам после завершения приема.
  6. Подключите гнездо для прослушивания к вашему IOCP.

Теперь вы можете опубликовать ряд AcceptEx() вызовы с использованием сокета прослушивания и нового сокета ‘accept’, который вы создаете следующим образом:

  1. Создать сокет с WSA_FLAG_OVERLAPPED задавать.
  2. Свяжите сокет с вашим IOCP.

Как указано выше, вы должны убедиться, что буфер и OVERLAPPED являются уникальными для каждого вызова и сохраняются до завершения.

Когда завершение происходит, вы должны сделать следующее ….

  1. Вызов setsockopt() с SO_UPDATE_ACCEPT_CONTEXT на принятом сокете, используя сокет прослушивания в качестве данных …
  2. Разблокируйте ваши адреса, используя GetAcceptExSockaddrs(),
  3. Обработайте любые данные (если вы выделили достаточно места в буфере для данных).

Обратите внимание, что по замыслу AcceptEx() может использоваться для принятия нового соединения и возврата начальных данных из этого соединения за одну операцию (это приводит к немного лучшей производительности в ситуациях, когда вы знаете, что вам всегда понадобятся некоторые данные, прежде чем вы сможете начать что-либо делать, но управлять ими ужасно сложно, если Вы хотите защитить от атаки типа «отказ в обслуживании», которую можно запустить, просто подключившись и НЕ отправляя данные — я писал об этом Вот).

Если вы не хотите AcceptEx() чтобы дождаться поступления данных, просто предоставьте буфер данных, который достаточно велик для того, чтобы адреса были возвращены, и передайте 0 в качестве «размера буфера». Это приведет к AcceptEx() действовать как перекрытый accept() и вернитесь, как только соединение будет установлено.

Обратите внимание, что первоначальный комментарий Мартина Джеймса к вашему вопросу на самом деле является ответом, который вы ищете. Не проходи outBufLen - ((sizeof (sockaddr_in) + 16) * 2), проходить 0,

10

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]