2009-10-20 24 views
8

Necesito mi programa escrito en C puro para detener la ejecución cuando se cierra stdin.¿Cómo verificar si stdin aún está abierto sin bloqueo?

Hay un trabajo indefinido en el ciclo principal del programa, y ​​no hay forma de que pueda usar controles de bloqueo (como getc()) allí (no se espera que lleguen datos en stdin; solo permanece abierto para tiempo desconocido).

Tengo la intención de utilizar la funcionalidad descrita en la realización del daemon de red alojado en inetd, xinetd o sus análogos - debe emitir datos en stdout mientras la conexión permanece abierta y terminar correctamente el trabajo cuando se cierra. Ahora el servicio de alojamiento elimina mi programa, ya que no se detendrá después de la finalización de la conexión.

Me pregunto si fctntl() con el indicador O_NONBLOCK aplicado al descriptor stdin me permitiría usar la función read() en modo no bloqueante? ¿Debo usar select() de alguna manera?

P.S. La información no se supone, pero podría llegar a stdin. Una forma de lectura sin bloqueo sería una respuesta para la pregunta.

Respuesta

6

select() hace exactamente lo que quiere: señal de que una operación (leer, en este caso) en un descriptor de archivo (archivo, socket, lo que sea) no se bloqueará.

#include <stdio.h> 
#include <sys/select.h> 

int is_ready(int fd) { 
    fd_set fdset; 
    struct timeval timeout; 
    int ret; 
    FD_ZERO(&fdset); 
    FD_SET(fd, &fdset); 
    timeout.tv_sec = 0; 
    timeout.tv_usec = 1; 
    //int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, 
    struct timeval *timeout); 
    return select(fd+1, &fdset, NULL, NULL, &timeout) == 1 ? 1 : 0; 
} 

Ahora puede comprobar un descriptor de archivo antes de su uso, por ejemplo, con el fin de vaciar el descriptor de archivo:

void empty_fd(int fd) { 
    char buffer[1024]; 
    while (is_ready(fd)) { 
     read(fd, buffer, sizeof(buffer)); 
    } 
} 

En su caso, utilizar fileno (entrada estándar) para obtener el descriptor de archivo de entrada estándar:

if (is_ready(fileno(stdin))) { 
    /* read stuff from stdin will not block */ 
} 
+0

'poll' es exactamente lo que OP quiere, y su interfaz es un poco más fácil que' select' cuando se trata de un conjunto pequeño y fijo de descriptores de archivos. – ephemient

0

¿Qué pasa con feof(stdin)?

+0

Eso no funcionará si no lee todos los datos. ¿Cómo leo todos los datos (basura por ejemplo) sin bloquear las operaciones? – Basilevs

+0

EOF se puede inyectar en un stdin abierto (por ejemplo, a través de Ctrl-D en Linux). No significa que stdin esté cerrado. –

1

No estoy seguro de si puede configurar O_NONBLOCK en stdin, pero select() o poll() definitivamente hará el trabajo.

+0

Sí, puede configurar O_NONBLOCK en stdin. Sin embargo, si su stdin se canaliza desde otro programa, es posible que ese programa no maneje muy bien su descriptor de archivo saliente. – ephemient

0

Sí, puede usar select (con un tiempo de espera cero). Sin embargo, no necesita configurar el descriptor de archivo como no bloqueante: si select le dice que el descriptor de archivo es legible, no se bloqueará definitivamente el read.

Por lo tanto, sondear el descriptor de archivo 0 occaisionalmente con select, y si es legible, read. Si read devuelve 0, significa que ha sido cerrado.

2

me pregunto si fctntl() con la bandera O_NONBLOCK aplica a la entrada estándar descriptor wo ¿Permitirme usar la función read() en modo no bloqueante?

Ejecutar stdin con O_NONBLOCK tiene ventajas sobre la selección. Select dice que hay algunos datos, pero no cuánto. Hay momentos en los que desea obtener todos los datos disponibles, pero no bloquearlos, independientemente de cuánto entre en la cola. Ejecutar seleccionar para cada personaje parece ser un trabajo muy ocupado ... O_NONBLOCK no funcionó para mí. Es una bandera interna, no expuesta en la mayoría de los controladores tty.

Echa un vistazo a ioctl (..., FIONBIO). Parece hacer el trabajo.

Cuestiones relacionadas