2009-10-09 14 views
27

¿Cómo se hace un socket sin bloqueo?¿Cómo cambio un socket TCP para que no sea bloqueante?

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

+1

Solo necesito convertir un Socket TCP en un socket que no sea de bloqueo. –

+1

No es confiable si no está haciendo una comprobación de errores y asumiendo que siempre está teniendo éxito. :) – Qix

Respuesta

19

¿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).

This forum thread tiene algunos puntos buenos cuando se trabaja con llamadas sin bloqueo.

+12

No creo que esta sea una buena respuesta. Le dices que debería ser confiable y luego publicas un hilo del foro que puede quedar rápidamente desactualizado. Solo mi opinión, pero alguien con su representante habría pensado que sería lo suficientemente considerado como para proporcionar una respuesta más completa que un enlace lento y un comentario rápido. – Matt

+4

@Matt. Perdón por decepcionar. Tenga en cuenta que esta respuesta tiene cuatro años y medio. Creo que mi respuesta revela mi frustración con la falta de detalles de la pregunta.Es difícil discutir con "He oído que hacerlo de la manera obvia no siempre es confiable". Todavía lo creo, no estoy seguro de cómo mejorar esto. – unwind

+0

Sí, después me di cuenta de la edad de la pregunta. Pensando que era nuevo porque alguien más lo actualizó y apareció en la lista de actividades ... oops. no importa. – Matt

12

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 bloqueante, funcione como accept(), recv() y etc., que son de naturaleza de bloqueo devolverá el error y errno se establecerá en EWOULDBLOCK. Puede sondear los conjuntos de descriptores de archivos para sondear en los sockets.

+0

¿Hay alguna otra forma de convertir un socket TCPIP a NON BLOCKING? No quiero confiar en estos métodos puede ser debido a mis experiencias pasadas –

+8

Esa ** es ** la forma de convertir un socket a no-bloqueo. Si puede ser específico sobre sus "experiencias pasadas" y por qué está convencido de que esto no funcionará, tal vez podamos ayudarlo. –

0

El mejor método para configurar un socket como no bloqueante en C es usar ioctl. Un ejemplo donde un socket aceptado se establece en no-bloqueo 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"); 
} 
+0

¿No es un zócalo asíncrono en lugar de un no bloqueo? – JuliandotNut

+0

En C/C++, en realidad no es bloqueante con conectores estándar/winsock. –

1

Generalmente se puede lograr el mismo efecto mediante el uso normal de bloqueo IO y multiplexación varias operaciones IO utilizando select(2), poll(2) o algún otro llamadas al sistema disponibles en su sistema.

Consulte The C10K problem para la comparación de enfoques de multiplexación IO escalable.

+0

No bajo POSIX, como estados 'man select' en la sección BUG,' select' puede informar socket para estar listo para 'leer', pero luego' read' puede bloquear. Entonces no es completamente lo mismo. – zoska

+0

Ahora nos hemos movido mucho más allá de los problemas de C10K. – Matt

+0

sondeo syscall (2) es O (n), epoll (2) es O (1), que es la única solución a C10K + – Anatoly

64

fcntl() siempre ha funcionado de manera confiable para mí. En cualquier caso, aquí es la función que utilizo para activar/desactivar el bloqueo de un conector:

#include <fcntl.h> 

/** 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 
} 
+0

Creo que usted pensó # include en lugar de import. – tambre

+0

Lo arreglé, gracias. –

+0

(flags <0) es incorrecto. Solo '-1' significa error, otros valores enteros negativos pueden ser máscaras de bits válidas. –

33

Usted está mal informado acerca fcntl() no siempre es fiable. No es verdad

Para marcar un zócalo como no bloqueante del 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 los núcleos> 2.6.27 También puede crear sockets no bloqueantes 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, por lo que tienden a establecer con fcntl().

+0

Vaya, me acabo de dar cuenta de que esta es una pregunta muy antigua. Ahh, creo que es hora de dar una respuesta actualizada. – Matt

+3

quizás viejo, pero sigue siendo útil. Tu respuesta parece ser exactamente lo que estaba buscando. –

+0

¿No es posible que su 'fcntl' interno falle antes de que falle el' fcntl' externo? – CMCDragonkai

Cuestiones relacionadas