В настоящее время я пытаюсь некоторые новые библиотеки (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 ()
Во-первых WSAOVERLAPPED
и буфер данных, который вы объявляете в стеке выше вашего вызова AcceptEx()
не будет существовать, когда произойдет завершение (если вы не звоните GetQueuedCompletionStatus()
в той же функции, что было бы немного странно). Вам необходимо их динамически распределять или объединять.
Во-вторых, вы заявляете, что связываете сокет с портом завершения после вызова AcceptEx()
, Это неверно. Вы должны сделать эти вещи, прежде чем позвонить AcceptEx()
,
WSA_FLAG_OVERLAPPED
задавать.AcceptEx()
динамически, используя сокет прослушивания и вызов WSAIoctl
(не обязательно, и код, который вы показываете, должен работать, но таким образом вы можете быть уверены, что вы получаете прослушивающий сокет от того же базового поставщика winsock и что он поддерживает AcceptEx ().GetAcceptExSockaddrs()
так же, как вы загружаете AcceptEx()
— он понадобится вам после завершения приема.Теперь вы можете опубликовать ряд AcceptEx()
вызовы с использованием сокета прослушивания и нового сокета ‘accept’, который вы создаете следующим образом:
WSA_FLAG_OVERLAPPED
задавать.Как указано выше, вы должны убедиться, что буфер и OVERLAPPED являются уникальными для каждого вызова и сохраняются до завершения.
Когда завершение происходит, вы должны сделать следующее ….
setsockopt()
с SO_UPDATE_ACCEPT_CONTEXT
на принятом сокете, используя сокет прослушивания в качестве данных …GetAcceptExSockaddrs()
,Обратите внимание, что по замыслу AcceptEx()
может использоваться для принятия нового соединения и возврата начальных данных из этого соединения за одну операцию (это приводит к немного лучшей производительности в ситуациях, когда вы знаете, что вам всегда понадобятся некоторые данные, прежде чем вы сможете начать что-либо делать, но управлять ими ужасно сложно, если Вы хотите защитить от атаки типа «отказ в обслуживании», которую можно запустить, просто подключившись и НЕ отправляя данные — я писал об этом Вот).
Если вы не хотите AcceptEx()
чтобы дождаться поступления данных, просто предоставьте буфер данных, который достаточно велик для того, чтобы адреса были возвращены, и передайте 0 в качестве «размера буфера». Это приведет к AcceptEx()
действовать как перекрытый accept()
и вернитесь, как только соединение будет установлено.
Обратите внимание, что первоначальный комментарий Мартина Джеймса к вашему вопросу на самом деле является ответом, который вы ищете. Не проходи outBufLen - ((sizeof (sockaddr_in) + 16) * 2)
, проходить 0
,
Других решений пока нет …