GNU/Linux >> Znalost Linux >  >> Linux

Jak zvládnout reventy linuxového socketu POLLERR, POLLHUP a POLLNVAL?

POLLNVAL znamená, že hodnota deskriptoru souboru je neplatná. Obvykle to znamená chybu ve vašem programu, ale můžete se spolehnout na poll vrací POLLNVAL pokud jste zavřeli deskriptor souboru a od té doby jste žádný soubor neotevřeli, mohlo dojít k opětovnému použití deskriptoru.

POLLERR je podobný chybovým událostem z select . Znamená to read nebo write volání by vrátilo chybový stav (např. I/O chyba). To nezahrnuje data mimo pásmo, která select signály přes jeho errorfds maska, ale poll signály přes POLLPRI .

POLLHUP v podstatě znamená, že to, co je na druhém konci spojení, uzavřelo svůj konec spojení. POSIX to popisuje jako

Zařízení bylo odpojeno. Tato událost a POLLOUT se vzájemně vylučují; do streamu nelze nikdy zapisovat, pokud došlo k zablokování.

To je pro terminál dostatečně jasné:terminál odešel (stejná událost, která generuje SIGHUP:relace modemu byla ukončena, okno emulátoru terminálu bylo zavřeno atd.). POLLHUP není nikdy odesláno pro běžný soubor. U trubek a zásuvek záleží na operačním systému. Linux nastaví POLLHUP když program na zapisovacím konci roury zavře roura a nastaví POLLIN|POLLHUP když druhý konec soketu uzavřel soket, ale POLLIN pouze pro vypnutí zásuvky. Nedávné *BSD sada POLLIN|POLLUP když zapisovací konec roury rouru uzavírá a chování soketů je variabilnější.


A POLLHUP znamená, že zásuvka již není připojena. V TCP to znamená, že FIN byl přijat a odeslán.

A POLLERR znamená, že soket dostal asynchronní chybu. V TCP to obvykle znamená, že byl přijat nebo odeslán RST. Pokud deskriptor souboru není soket, POLLERR může znamenat, že zařízení nepodporuje dotazování.

Pro obě výše uvedené podmínky je deskriptor souboru soketu stále otevřený a ještě nebyl uzavřen (ale shutdown() možná již byl volán). A close() na deskriptoru souboru uvolní prostředky, které jsou stále rezervovány jménem soketu. Teoreticky by mělo být možné okamžitě znovu použít soket (např. s jiným connect() zavolat).

A POLLNVAL znamená, že deskriptor souboru soketu není otevřený. Byla by chyba close() to.


Záleží na přesné povaze chyby. Použijte getockopt() k zobrazení problému:

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

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

Nejjednodušší způsob je předpokládat, že socket již není v žádném případě použitelný a zavřít jej.


Minimální příklad FIFO

Jakmile pochopíte, kdy tyto podmínky nastanou, mělo by být snadné vědět, co s nimi dělat.

anketa.c

#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");
        }
    }
}

GitHub upstream.

Kompilace s:

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

Použití:

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

Na jiném shellu:

printf a >poll0.tmp

POLLHUP

Pokud zdroj neupravíte:./poll.out výstupy:

loop
POLLIN n=1 buf=a
loop
POLLHUP
loop

Takže:

  • POLLIN stane se, když je vstup dostupný
  • POLLHUP nastane, když je soubor uzavřen pomocí printf
  • close(pfd.fd); a pfd.fd *= -1; vyčistit věci a přestaneme dostávat POLLHUP
  • poll visí navždy

Toto je normální operace.

Nyní můžete odvolat FIFO, aby počkal na další open , nebo ukončete smyčku, pokud jste hotovi.

POLLNAL

Pokud zakomentujete pfd.fd *= -1; :./poll.out tisky:

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

a smyčky navždy.

Takže:

  • POLLIN a POLLHUP a close stalo jako předtím
  • protože jsme nenastavili pfd.fd na záporné číslo, poll stále zkouší používat fd že jsme zavřeli
  • toto stále vrací POLLNVAL navždy

Vidíme tedy, že se to stát nemělo, a ukazuje to na chybu ve vašem kódu.

POLLERR

Nevím, jak vygenerovat POLLERR s FIFO. Dejte mi vědět, jestli existuje způsob. Ale mělo by to být možné s file_operations ovladače zařízení.

Testováno v Ubuntu 14.04.


Linux
  1. Jak zjistit velikost vyrovnávací paměti soketu linuxu

  2. Jak mohu vidět velikost souborů a adresářů v linuxu?

  3. Jak přesunu soubory a adresáře do nadřazené složky v Linuxu?

  1. Jak Linux zachraňuje pomalé počítače (a planetu)

  2. Jak otevírat a zavírat adresáře v terminálu Linux

  3. Jak vytvořit alias a používat příkaz Alias ​​v Linuxu

  1. Jak zkontrolovat verzi OS a Linuxu

  2. Jak identifikovat karty/porty HBA a WWN v Linuxu

  3. Jak určit dobu připojení soketu v systému Linux