windows - En Win32, ¿hay alguna manera de probar si un socket no es bloqueante?
winapi sockets (2)
En Win32, ¿hay alguna manera de probar si un socket no es bloqueante?
En sistemas POSIX, haría 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 se establece usando ioctl con FIONBIO, pero no parece haber 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?
Una respuesta un poco más larga sería: No, pero generalmente sabrá si es o no, porque está relativamente bien definida.
Todos los sockets se bloquean a menos que los ioctlsocket()
explícitamente ioctlsocket()
con FIONBIO
o los entregue a WSAAsyncSelect
o WSAEventSelect
. Las dos últimas funciones cambian "secretamente" el socket al no bloqueo.
Como 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 estar bloqueado y superpuesto al mismo tiempo, lo que no parece inmediatamente intuitivo, pero tiene sentido porque proviene de paradigmas opuestos (preparación versus finalización).
Anteriormente, podía llamar a 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 multiplataforma para establecer / obtener el modo de bloqueo, aunque no hace exactamente lo que desea:
/// @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;
}