2012-02-09 13 views
7

Ho un semplice pezzo di codice che scrive periodicamente i dati su un file system che viene passato ad esso. Il fd sarà probabilmente una pipe o socket ma potrebbe potenzialmente essere qualsiasi cosa. Sono in grado di rilevare quando il socket/pipe è chiuso/rotto ogni volta che scrivo() ad esso, dal momento che ottengo un errore EPIPE (sto ignorando SIGPIPE). Ma non scrivo tutto il tempo, e quindi non posso rilevare una presa chiusa per molto tempo. Ho bisogno di reagire alla chiusura al più presto. C'è un metodo per controllare il fd senza dover scrivere()? Potrei quindi farlo periodicamente se non scrivo nulla.Linux: Verifica se un socket/pipe è interrotto senza fare una read()/write()

+2

selezionare, sondaggio, e epoll saranno tutti vi dirà –

+0

Grazie per la risposta, ma non sono sicuro come fare questo lavoro con tubi. Ho provato una chiamata select() con il mio fd nella scrittura e salvo i fdset, e il risultato della chiamata non cambia quando la pipe è rotta (restituire sempre il mio fd nel set di scrittura). Ho anche provato poll() con tutti gli eventi impostati e ancora non c'è differenza. – gimmeamilk

+0

Non spingere il tuo fd nei set di scrittura. Solo l'eccetto. –

risposta

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

Questo funziona per me. Nota che i socket non sono esattamente pipe e quindi mostrano un comportamento differente (-> usa POLLRDHUP).

+0

Aha! Ho avuto un errore di battitura e stavo controllando gli eventi in uscita invece di revents. Molte grazie, ha funzionato alla grande. – gimmeamilk

+1

Ottima risposta. Sono troppo abituato a selezionare() chiama. Devo cercare di evolvere definitivamente su questo punto. +1 –

2

Prova con il parametro di selezione ed i suoi errorfds:

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

Grazie, ma ho provato ad aggiungere il mio fd al set di eccezioni e non ho potuto farlo funzionare in modo diverso quando la pipe era rotta. (Potrebbe funzionare bene con il socket, non ho ancora provato dal momento che il mio setup attuale mi da un pipe) – gimmeamilk

1

Belle risposte, mi piacciono ... Ho anche bisogno di uscire dalla select habbit e nel (e) sondaggio.

Ecco alcuni metodi più tradizionali, se avete bisogno di loro:

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

Questo si cerca di duplicare la presa/fd. E 'molto più semplice di quanto negli sguardi, ho lasciato un sacco di debug.

/* 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; 
} 
Problemi correlati