2011-03-30 13 views
9

En Win32, ¿hay alguna manera de comprobar si un socket no bloquea?En Win32, ¿hay alguna manera de probar si un socket no es bloqueante?

En sistemas POSIX, me gustaría hacer algo como lo siguiente:

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

Sin embargo, los sockets de Windows no son compatibles con fcntl(). El modo sin bloqueo es establece usando ioctl con FIONBIO, pero no parece que haya una forma de obtener el modo actual sin bloqueo usando ioctl.

¿Hay alguna otra llamada en Windows que pueda usar para determinar si el socket está actualmente en modo no bloqueante?

Respuesta

6

Una respuesta un poco más larga sería: No, pero normalmente sabrá si es o no, porque está relativamente bien definida.

Todos los enchufes están bloqueando a menos que les ioctlsocket() explícitamente FIONBIO o entregarlos a cualquiera WSAAsyncSelect o WSAEventSelect. Las dos últimas funciones cambian "secretamente" el socket al no bloqueo.

Ya sabe si ha llamado a una de esas 3 funciones, aunque no puede consultar el estado, todavía se conoce. La excepción obvia es si ese socket proviene de una biblioteca de terceros de la cual no se sabe exactamente qué ha estado haciendo con el socket.

Sidenote: Curiosamente, un socket puede bloquearse y superponerse al mismo tiempo, lo que no parece inmediatamente intuitivo, pero tiene sentido porque proviene de paradigmas opuestos (preparación frente a terminación).

+1

Si acepto() una conexión, ¿el nuevo socket heredan el ¿estado de bloqueo de la toma de audición? –

2

Anteriormente, podía llamar al WSAIsBlocking para determinar esto. Si está administrando código heredado, esta puede ser una opción.

De lo contrario, podría escribir una capa de abstracción simple sobre la API de socket. Como todos los sockets están bloqueados por defecto, puede mantener un indicador interno y forzar todas las operaciones de socket a través de su API para que siempre sepa el estado.

Aquí hay un fragmento de plataforma cruzada para establecer/obtener el modo de bloqueo, a pesar de que no hace exactamente lo que quiere:

/// @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; 
} 
Cuestiones relacionadas