2014-07-16 3 views
8

Mi chiedo cosa si dovrebbe fare quando il sondaggio imposta questi bit? Chiudere la presa, ignorarla o cosa?Come gestire il socket di Linux revents POLLERR, POLLHUP e POLLNVAL?

+1

Nessun contesto a questa domanda, qual è la vostra intenzione? – Kris

+6

Ne ha davvero bisogno? Sto solo chiedendo le migliori pratiche ... – user3790882

+0

@ user3790882 _ 'sto solo chiedendo le migliori pratiche'_ Dovresti essere un po' più elaborato su questo punto però: P ... –

risposta

11

A POLLHUP significa che la presa non è più collegata. In TCP, questo significa che FIN è stata ricevuta e inviata.

A POLLERR significa che il socket ha ricevuto un errore asincrono. In TCP, questo in genere significa che è stato ricevuto o inviato un RST. Se il descrittore di file non è un socket, POLLERR potrebbe indicare che il dispositivo non supporta il polling.

Per entrambe le condizioni precedenti, il descrittore del file socket è ancora aperto e non è stato ancora chiuso (ma è possibile che sia già stato chiamato shutdown()). Un close() sul descrittore di file rilascerà le risorse che sono ancora riservate per conto del socket. In teoria, dovrebbe essere possibile riutilizzare immediatamente la presa (ad es. Con un'altra chiamata connect()).

A POLLNVAL indica che il descrittore del file socket non è aperto. Sarebbe un errore a close() esso.

8

Dipende dalla natura esatta dell'errore. Utilizzare getsockopt() per visualizzare il problema:

int error = 0; 
socklen_t errlen = sizeof(error); 
getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&error, &errlen); 

Valori: http://www.xinotes.net/notes/note/1793/

Il modo più semplice è quello di presumere che la presa non più utilizzabile in ogni caso è e chiuderlo.

+0

Per me, stavo ricevendo POLLERR ma ... non avevo modo di scoprire quale fosse l'errore! Questa risposta sembra la migliore perché risponde alla domanda più generale di "best practice" per la gestione di POLLERR per la programmazione di rete. –

+0

Non penso che funzioni nel caso generale. Almeno, Linux non documenta che può essere usato in questo modo. 'SO_ERROR' è documentato per restituire lo stato di errore del socket, ma il suo utilizzo per rilevare lo stato di errore del socket è descritto solo per la chiamata' connect() 'e non per altri. – jxh

2

POLLNVAL significa che il valore del descrittore di file non è valido. Solitamente indica un errore nel tuo programma, ma puoi fare affidamento su restituendo POLLNVAL se hai chiuso un descrittore di file e non hai aperto alcun file da quel momento che potrebbe aver riutilizzato il descrittore.

POLLERR è simile agli eventi di errore da select. Indica che una chiamata read o write restituirebbe una condizione di errore (ad esempio, errore I/O). Questo non include i dati fuori banda che inviano i segnali select tramite la sua maschera errorfds ma i segnali poll tramite POLLPRI.

POLLHUP significa fondamentalmente che ciò che è all'altro capo della connessione ha chiuso la sua estremità della connessione. POSIX lo descrive come

Il dispositivo è stato disconnesso. Questo evento e POLLOUT si escludono a vicenda; uno stream non può mai essere scritto se si verifica un hangup.

Questo è abbastanza evidente per un terminale: il terminale è scomparso (stesso evento che genera un SIGHUP: la sessione modem è stato terminato, la finestra di terminale è stato chiuso, ecc). POLLHUP non viene mai inviato per un file normale. Per tubi e prese, it depends on the operating system. Linux imposta POLLHUP quando il programma sull'estremità di scrittura di un tubo chiude il tubo e imposta POLLIN|POLLHUP quando l'altra estremità di un socket chiude il socket, ma POLLIN solo per un arresto del socket. Recenti * BSD ha impostato POLLIN|POLLUP quando la fine della scrittura di un pipe chiude la pipe e il comportamento per i socket è più variabile.

0

esempio FIFO minimo

Una volta capito quando queste condizioni si verificano, dovrebbe essere facile sapere cosa fare con loro.

#define _XOPEN_SOURCE 700 
#include <fcntl.h> /* creat, O_CREAT */ 
#include <poll.h> /* poll */ 
#include <stdio.h> /* printf, puts, snprintf */ 
#include <stdlib.h> /* EXIT_FAILURE, EXIT_SUCCESS */ 
#include <unistd.h> /* read */ 

int main(void) { 
    char buf[1024]; 
    int fd, n; 
    short revents; 
    struct pollfd pfd; 

    fd = open("poll0.tmp", O_RDONLY | O_NONBLOCK); 
    pfd.fd = fd; 
    pfd.events = POLLIN; 
    while (1) { 
     puts("loop"); 
     poll(&pfd, 1, -1); 
     revents = pfd.revents; 
     if (revents & POLLIN) { 
      n = read(pfd.fd, buf, sizeof(buf)); 
      printf("POLLIN n=%d buf=%.*s\n", n, n, buf); 
     } 
     if (revents & POLLHUP) { 
      printf("POLLHUP\n"); 
      close(pfd.fd); 
      pfd.fd *= -1; 
     } 
     if (revents & POLLNVAL) { 
      printf("POLLNVAL\n"); 
     } 
     if (revents & POLLERR) { 
      printf("POLLERR\n"); 
     } 
    } 
} 

compilazione con:

gcc -o poll.out -std=c99 poll.c 

utilizzati:

sudo mknod -m 666 poll0.tmp p 
./poll.out 

In un'altra shell:

printf a >poll0.tmp 

POLLHUP

Se non si modifica la fonte: ./poll.out uscite:

loop 
POLLIN n=1 buf=a 
loop 
POLLHUP 
loop 

Quindi:

  • POLLIN accade quando l'ingresso diventa disponibile
  • POLLHUP accade quando il file viene chiuso dalla printf
  • close(pfd.fd); e pfd.fd *= -1; ripulire le cose e smettiamo di ricevere POLLHUP
  • poll pende sempre

Questa è l'operazione normale.

Ora è possibile ripristinare il FIFO per attendere il successivo open oppure uscire dal ciclo se si è terminato.

POLLNAL

Se si commento fuori pfd.fd *= -1;: ./poll.out stampe:

POLLIN n=1 buf=a 
loop 
POLLHUP 
loop 
POLLNVAL 
loop 
POLLNVAL 
... 

e loop per sempre.

Quindi:

  • POLLIN e POLLHUP e close successo come prima
  • dato che non abbiamo impostato pfd.fd ad un numero negativo, poll continua a cercare di utilizzare il fd che abbiamo chiuso
  • questo mantiene restituendo POLLNVAL per sempre

Quindi vediamo che questo non dovrebbe essere successo e indica un bug nel codice.

POLLERR

non so come generare un POLLERR con FIFO. Fammi sapere se c'è un modo. Ma dovrebbe essere possibile con file_operations di un driver di periferica.

Testato in Ubuntu 14.04.

Problemi correlati