GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Wie gehe ich mit den Linux-Socket-Revents POLLERR, POLLHUP und POLLNVAL um?

POLLNVAL bedeutet, dass der Dateideskriptorwert ungültig ist. Normalerweise weist es auf einen Fehler in Ihrem Programm hin, aber Sie können sich auf poll verlassen Rückgabe von POLLNVAL wenn Sie einen Dateideskriptor geschlossen und seitdem keine Datei mehr geöffnet haben, könnte der Deskriptor wiederverwendet worden sein.

POLLERR ähnelt den Fehlerereignissen von select . Es zeigt an, dass ein read oder write Aufruf würde eine Fehlerbedingung (z. B. I/O-Fehler) zurückgeben. Dies schließt keine Out-of-Band-Daten ein, die select sind Signale über seinen errorfds Maske, aber poll Signale über POLLPRI .

POLLHUP bedeutet im Grunde, dass das, was am anderen Ende der Verbindung ist, sein Ende der Verbindung geschlossen hat. POSIX beschreibt es als

Das Gerät wurde getrennt. Dieses Event und POLLOUT schließen sich gegenseitig aus; ein Stream kann niemals beschreibbar sein, wenn ein Hangup aufgetreten ist.

Für ein Terminal ist dies klar genug:Das Terminal ist weg (dasselbe Ereignis, das ein SIGHUP erzeugt:Die Modemsitzung wurde beendet, das Fenster des Terminalemulators wurde geschlossen usw.). POLLHUP wird nie für eine normale Datei gesendet. Bei Pipes und Sockets hängt es vom Betriebssystem ab. Linux setzt POLLHUP wenn das Programm am schreibenden Ende einer Pipe die Pipe schließt und POLLIN|POLLHUP setzt wenn das andere Ende eines Sockets den Socket schloss, aber POLLIN nur für ein Socket-Shutdown. Neuer *BSD-Satz POLLIN|POLLUP wenn das schreibende Ende einer Pipe die Pipe schließt, und das Verhalten für Sockets variabler ist.


Ein POLLHUP bedeutet, dass die Steckdose nicht mehr verbunden ist. In TCP bedeutet dies, dass FIN empfangen und gesendet wurde.

Ein POLLERR bedeutet, dass der Socket einen asynchronen Fehler erhalten hat. Bei TCP bedeutet dies normalerweise, dass ein RST empfangen oder gesendet wurde. Wenn der Dateideskriptor kein Socket ist, POLLERR könnte bedeuten, dass das Gerät Polling nicht unterstützt.

Für beide oben genannten Bedingungen ist der Socket-Dateideskriptor noch geöffnet und wurde noch nicht geschlossen (aber shutdown() wurde vielleicht schon angerufen). Ein close() im Dateideskriptor gibt Ressourcen frei, die noch für den Socket reserviert sind. Theoretisch sollte es möglich sein, den Socket sofort wiederzuverwenden (z. B. mit einem anderen connect() anrufen).

Ein POLLNVAL bedeutet, dass der Socket-Dateideskriptor nicht geöffnet ist. Es wäre ein Fehler zu close() es.


Es hängt von der genauen Fehlerart ab. Verwenden Sie getsockopt(), um das Problem zu sehen:

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

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

Am einfachsten geht man davon aus, dass der Socket ohnehin nicht mehr nutzbar ist und schließt ihn.


Minimales FIFO-Beispiel

Sobald Sie verstehen, wann diese Bedingungen auftreten, sollten Sie leicht wissen, was damit zu tun ist.

poll.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.

Kompilieren mit:

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

Verwendung:

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

Auf einer anderen Shell:

printf a >poll0.tmp

UMFRAGE

Wenn Sie die Quelle nicht ändern:./poll.out Ausgaben:

loop
POLLIN n=1 buf=a
loop
POLLHUP
loop

Also:

  • POLLIN geschieht, wenn Eingaben verfügbar werden
  • POLLHUP passiert, wenn die Datei durch printf geschlossen wird
  • close(pfd.fd); und pfd.fd *= -1; aufräumen und wir hören auf POLLHUP zu empfangen
  • poll hängt für immer

Dies ist der normale Vorgang.

Sie könnten jetzt den FIFO erneut anweisen, auf den nächsten open zu warten , oder beenden Sie die Schleife, wenn Sie fertig sind.

POLLNAL

Wenn Sie pfd.fd *= -1; auskommentieren :./poll.out druckt:

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

und Endlosschleifen.

Also:

  • POLLIN und POLLHUP und close geschah wie zuvor
  • da wir pfd.fd nicht gesetzt haben zu einer negativen Zahl, poll versucht weiterhin, den fd zu verwenden dass wir geschlossen haben
  • dies gibt ständig POLLNVAL zurück für immer

Wir sehen also, dass dies nicht hätte passieren dürfen, und weist auf einen Fehler in Ihrem Code hin.

POLLER

Ich weiß nicht, wie ich einen POLLERR generieren soll mit FIFOs. Lassen Sie mich wissen, ob es einen Weg gibt. Mit file_operations sollte es aber möglich sein eines Gerätetreibers.

Getestet in Ubuntu 14.04.


Linux
  1. Wie Linux langsame Computer (und den Planeten) rettet

  2. So öffnen und schließen Sie Verzeichnisse im Linux-Terminal

  3. So bestimmen Sie die Betriebszeit der Socket-Verbindung unter Linux

  4. Wie interpretiere und behebe ich einen Eingabe-/Ausgabefehler in Linux?

  5. Wie können die Schwachstellen Spectre und Meltdown auf Linux-Systemen gemindert werden?

So löschen (leeren) Sie den DNS-Cache unter Windows, MacOS und Linux

Wie man den Befehl fuser unter Linux verwendet und optimal nutzt

So finden und listen Sie die Dateien rekursiv nach Datum in Linux auf

So finden Sie die PID und PPID eines Prozesses in Linux

So installieren und verwenden Sie den Ack-Befehl unter Linux

Linux perf:So verwenden Sie den Befehl und den Profiler