¿Cómo cambio un socket TCP para que no sea bloqueante?

¿Cómo se hace un socket sin locking?

fcntl() función fcntl() , pero he oído que no siempre es confiable.

¿Qué quiere decir con “no siempre confiable”? Si el sistema tiene éxito en configurar su socket no non-blocking, será no bloqueante. Las operaciones de socket devolverán EWOULDBLOCK si bloquearían la necesidad de bloquear (por ejemplo, si el buffer de salida está lleno y usted está llamando a enviar / escribir con demasiada frecuencia).

Este hilo del foro tiene algunos puntos buenos cuando se trabaja con llamadas sin locking.

fcntl() siempre ha funcionado de manera confiable para mí. En cualquier caso, aquí está la función que uso para habilitar / deshabilitar el locking en un socket:

 #include  /** Returns true on success, or false if there was an error */ bool SetSocketBlockingEnabled(int fd, bool blocking) { if (fd < 0) return false; #ifdef _WIN32 unsigned long mode = blocking ? 0 : 1; return (ioctlsocket(fd, FIONBIO, &mode) == 0) ? true : false; #else int flags = fcntl(fd, F_GETFL, 0); if (flags == -1) return false; flags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK); return (fcntl(fd, F_SETFL, flags) == 0) ? true : false; #endif } 

Está mal informado acerca de que fcntl() no siempre es confiable. No es verdad

Para marcar un socket como no bloqueante, el código es tan simple como:

 // where socketfd is the socket you want to make non-blocking int status = fcntl(socketfd, F_SETFL, fcntl(socketfd, F_GETFL, 0) | O_NONBLOCK); if (status == -1){ perror("calling fcntl"); // handle the error. By the way, I've never seen fcntl fail in this way } 

En Linux, en Kernels> 2.6.27 también puede crear sockets sin locking desde el principio utilizando socket() y accept4() .

p.ej

  // client side int socketfd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); // server side - see man page for accept4 under linux int socketfd = accept4( ... , SOCK_NONBLOCK); 

Se ahorra un poco de trabajo, pero es menos portátil, así que tiendo a configurarlo con fcntl() .

fcntl() o ioctl() se utilizan para establecer las propiedades de las transmisiones de archivos. Cuando use esta función para hacer que un socket no sea bloqueado, funcione como accept() , recv() y etc., que son de naturaleza de locking devolverá el error y errno se establecerá en EWOULDBLOCK . Puede sondear los conjuntos de descriptores de archivos para sondear en los sockets.

En general, puede lograr el mismo efecto al usar IO de locking normal y multiplexar varias operaciones IO usando select(2) , poll(2) u otras llamadas al sistema disponibles en su sistema.

Consulte el problema de C10K para la comparación de enfoques de multiplexación IO escalable.

Sé que es una vieja pregunta, pero para todos los usuarios de google que terminan aquí buscando información sobre cómo lidiar con los sockets de locking y no de locking aquí hay una explicación detallada de las diferentes formas de lidiar con los modos de E / S de los sockets – http://dwise1.net/pgm/sockets/blocking.html .

Sumario rápido:

  • Entonces, ¿por qué Sockets Block?

  • ¿Cuáles son las técnicas básicas de progtwigción para lidiar con el locking de sockets?

    • Tener un diseño que no se preocupe por bloquear
    • Usando seleccionar
    • Usar tomas sin locking.
    • Uso de multihilo o multitarea

El mejor método para configurar un socket como no bloqueante en C es usar ioctl. Un ejemplo donde un socket aceptado está configurado como no-blocking es el siguiente:

 long on = 1L; unsigned int len; struct sockaddr_storage remoteAddress; len = sizeof(remoteAddress); int socket = accept(listenSocket, (struct sockaddr *)&remoteAddress, &len) if (ioctl(socket, (int)FIONBIO, (char *)&on)) { printf("ioctl FIONBIO call failed\n"); }