В Win32 есть ли способ проверить, является ли сокет неблокирующим? - PullRequest
10 голосов
/ 30 марта 2011

В Win32 есть ли способ проверить, неблокируется ли сокет?

В системах POSIX я бы сделал что-то вроде следующего:

int is_non_blocking(int sock_fd) {
    flags = fcntl(sock_fd, F_GETFL, 0);
    return flags & O_NONBLOCK;
}

Однако сокеты Windows не поддерживают fcntl (). Режим неблокирования установлен с использованием ioctl с FIONBIO, но, похоже, нет способа получить текущий режим неблокирования с использованием ioctl.

Есть ли какой-нибудь другой вызов в Windows, который я могу использовать, чтобы определить, находится ли сокет в настоящее время в неблокирующем режиме?

Ответы [ 2 ]

7 голосов
/ 31 марта 2011

Немного более длинный ответ будет: Нет, но вы обычно будете знать, так ли это, потому что он относительно четко определен.

Все сокеты блокируются, если вы явно не ioctlsocket() их с помощью FIONBIO или передайте их либо WSAAsyncSelect, либо WSAEventSelect.Последние две функции «тайно» изменяют сокет на неблокирующий.

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

Sidenote: Как ни странно, сокет может блокироваться и перекрываться одновременновремя, которое не сразу кажется интуитивным, но оно имеет смысл, потому что оно исходит из противоположных парадигм (готовность против завершения).

5 голосов
/ 12 октября 2015

Ранее вы могли вызвать WSAIsBlocking , чтобы определить это. Если вы управляете унаследованным кодом, это все еще может быть вариантом.

В противном случае вы можете написать простой уровень абстракции поверх API сокетов. Поскольку все сокеты по умолчанию блокируются, вы можете сохранить внутренний флаг и принудительно выполнить все операции сокетов через API, чтобы всегда знать состояние.

Вот кроссплатформенный фрагмент кода для установки / получения режима блокировки, хотя он не выполняет то, что вам нужно:

/// @author Stephen Dunn
/// @date 10/12/15
bool set_blocking_mode(const int &socket, bool is_blocking)
{
    bool ret = true;

#ifdef WIN32
    /// @note windows sockets are created in blocking mode by default
    // currently on windows, there is no easy way to obtain the socket's current blocking mode since WSAIsBlocking was deprecated
    u_long flags = is_blocking ? 0 : 1;
    ret = NO_ERROR == ioctlsocket(socket, FIONBIO, &flags);
#else
    const int flags = fcntl(socket, F_GETFL, 0);
    if ((flags & O_NONBLOCK) && !is_blocking) { info("set_blocking_mode(): socket was already in non-blocking mode"); return ret; }
    if (!(flags & O_NONBLOCK) && is_blocking) { info("set_blocking_mode(): socket was already in blocking mode"); return ret; }
    ret = 0 == fcntl(socket, F_SETFL, is_blocking ? flags ^ O_NONBLOCK : flags | O_NONBLOCK);
#endif

    return ret;
}
...