Winsock - подождите с вызовом accept (), пока клиент действительно не попытается подключиться

Я создаю сервер на C ++ с помощью Winsock API. Мне интересно, есть ли возможность вызвать функцию accept () только в том случае, если какое-то соединение действительно идет, поэтому мне не нужно блокировать мой поток на accept (). Другими словами, я хотел бы, чтобы мой поток ждал и вызывал функцию accept () только тогда, когда клиент пытается подключиться. Это возможно?


person Ema Siema    schedule 08.06.2013    source источник
comment
Используйте select (), чтобы указать, когда accept () не будет блокироваться.   -  person brian beuning    schedule 08.06.2013
comment
Или используйте сокет в асинхронном режиме. Используйте WSAAsyncEvent() или WSAAsyncSelect(), чтобы Winsock уведомлял вас о новом подключении.   -  person Remy Lebeau    schedule 08.06.2013


Ответы (1)


Поскольку вы используете Winsock, вы можете использовать специфичную для Microsoft функцию расширения AcceptEx. Это позволяет вам выполнять принятие как «перекрывающийся ввод-вывод», что концептуально означает, что принятие выполняется в фоновом режиме, и вы можете иногда заходить и проверять, произошло это или нет, либо проверив OverlappedResult, либо выполнив Подождите на OverlappedHandle. AcceptEx также дополнительно выполнит первый прием.

Без написания всего кода и его тщательного тестирования должно работать примерно следующее:

// The following:
//   Has no error checking
//   Assumes sListen is a bound listening socket
//   Some other assumptions I've not listed :)

// Allocate space to store the two sockaddr's that AcceptEx will give you
// 
char lpOutputBuffer[sizeof((sockaddr_in)+16) * 2];

SOCKET sAccept = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
WSAOVERLAPPED olOverlap;

ZeroMemory(&olOverlap, sizeof(WSAOVERLAPPED));
olOverlap.hEvent = WSACreateEvent();

DWORD dwBytes;

BOOL bAcceptRet =
    AcceptEx(sListen, // the listen socket
             sAccept, // the socket to use for the accepted connection
             lpOutputBuffer, // where to store the received information
             0, // don't do a receive, just store the local and remote addresses
             sizeof((sockaddr_in)+16), // size of the local address area
             sizeof((sockaddr_in)+16), // size of the remote address area
             &dwBytes, // set to received bytes if we complete synchronously
             &olOverlap); // our overlapped structure

if (bAcceptRet) {
    // the function completed synchronously.
    // lpOutputBuffer should contain the address information.
    // sAccept should be a connected socket
} else {
    // the function didn't complete synchronously, so is the accept Pending?
    if (ERROR_IO_PENDING == WSAGetLastError()) {
        // in this case, our Accept hasn't happened yet...
        // later in our code we can do the following to check if an accept has occurred:
        // note that the FALSE tells WSAGetOverlappedResult not to wait for the I/O to complete
        // it should return immediately
        ...
        DWORD dwFlags;
        if (WSAGetOverlappedResult(sListen, &olOverlap, &dwBytes, FALSE, &dwFlags)) {
            // the accept has succeeded, so do whatever we need to do with sAccept.
        }
        ...
    }
}

Конечно, это очень быстрый, скомпилированный фрагмент, вероятно, неработающего, не компилируемого кода, но он должен дать вам представление о том, как вы могли бы сделать что-то похожее на то, что вы хотите, и где искать.

Между прочим, технически нет необходимости устанавливать параметр hEvent структуры WSAOVERLAPPED, но это позволяет вам фактически дождаться завершения запроса:

if (WAIT_OBJECT_0 == WaitForSingleObject(olOverlap.hEvent, INFINITE)) {
    // The accept occurred, so do something with it
}

Теперь я подожду, пока кто-нибудь укажет на огромные вопиющие ошибки в моем коде ...

person icabod    schedule 12.06.2013