2012-02-09 16 views
7

Tengo un código simple que periódicamente escribe datos en un archivo fd que se le pasa. Es probable que el fd sea una tubería o un zócalo, pero podría ser cualquier cosa. Puedo detectar cuando la toma/tubería está cerrada/rota cada vez que escribo() en ella, ya que recibo un error EPIPE (estoy ignorando SIGPIPE). Pero no escribo todo el tiempo y, por lo tanto, es posible que no detecte un socket cerrado durante mucho tiempo. Necesito reaccionar al cierre lo antes posible. ¿Hay algún método para verificar el fd sin tener que escribir()? Podría hacer esto periódicamente si no escribo nada.Linux: Comprobando si un conector/tubería está roto sin leer()/write()

+2

selecto, encuesta, y epoll todos le dirán –

+0

Gracias por la respuesta, pero no estoy seguro de cómo hacer este trabajo con tubería. Probé una llamada select() con mi fd en la escritura y excepto fdsets, y el resultado de la llamada no cambia cuando la tubería está rota (siempre devuelve mi fd en el conjunto de escritura). También probé poll() con todos los eventos configurados y nuevamente no hay diferencia. – gimmeamilk

+0

No inserte su fd en los archivos de escritura. Solo el excepto uno. –

Respuesta

8
struct pollfd pfd = {.fd = yourfd, .events = POLLERR}; 
if (poll(&pfd, 1, whatever) < 0) abort(); 
if (pfd.revents & POLLERR) printf("pipe is broken\n"); 

Esto funciona para mí. Tenga en cuenta que los sockets no son exactamente tubos y muestran un comportamiento diferente (-> use POLLRDHUP).

+0

¡Ajá! Tuve un error tipográfico y estaba verificando eventos en el camino de salida en lugar de hacerlo. Muchas gracias, esto funcionó muy bien. – gimmeamilk

+1

Gran respuesta. Estoy demasiado acostumbrado a la llamada select(). Definitivamente debo tratar de evolucionar en ese punto. +1 –

2

intento con selecto y sus errorfds parámetro:

int **select**(int nfds, fd_set *restrict readfds, 
     fd_set *restrict writefds, **fd_set *restrict errorfds**, 
     struct timeval *restrict timeout); 
+1

Gracias, pero intenté agregar mi fd al conjunto de excepciones y no pude lograr que se comportara de manera diferente cuando se rompió el tubo. (Podría funcionar bien con el zócalo; no lo he intentado todavía, ya que mi configuración actual me da una tubería) – gimmeamilk

1

Buenas respuestas, me gustan ... También necesito salir del habbit selecto y entrar en la encuesta (e).

He aquí algunos de los métodos más tradicionales, si los necesita:

/* check whether a file-descriptor is valid */ 
int fd_valid(int fd) 
{ 
    if (fcntl(fd, F_GETFL) == -1 && errno == EBADF) return FALSE; 
    return TRUE; 
}  

Esto se intenta duplicar la toma/fd. Es mucho más simple que en las miradas, me dejó un montón de depuración en.

/* check a file descriptor */ 
int fd_check(int i) { 
    int fd_dup = dup(i); 
    if (fd_dup == -1) { 
     strcpy(errst, strerror(errno)); 
     // EBADF oldfd isn’t an open file descriptor, or newfd is out of the allowed range for file descriptors. 
     // EBUSY (Linux only) This may be returned by dup2() during a race condition with open(2) and dup(). 
     // EINTR The dup2() call was interrupted by a signal; see signal(7). 
     // EMFILE The process already has the maximum number of file descriptors open and tried to open a new one. 

     if (errno == EBADF) { 
      return FALSE; 
     } 

     return TRUE; 
    } 
    close(fd_dup); 
    return TRUE; 
} 
Cuestiones relacionadas