GNU/Linux >> Belajar Linux >  >> Linux

Bagaimana cara menangani revent Linux socket POLLERR, POLLHUP dan POLLNVAL?

POLLNVAL berarti nilai deskriptor file tidak valid. Ini biasanya menunjukkan kesalahan dalam program Anda, tetapi Anda dapat mengandalkan poll mengembalikan POLLNVAL jika Anda telah menutup deskriptor file dan belum membuka file apa pun sejak saat itu, file tersebut mungkin telah menggunakan kembali deskriptor tersebut.

POLLERR mirip dengan peristiwa kesalahan dari select . Ini menunjukkan bahwa read atau write panggilan akan mengembalikan kondisi kesalahan (misalnya kesalahan I/O). Ini tidak termasuk data out-of-band yang select sinyal melalui errorfds miliknya mask tapi poll sinyal melalui POLLPRI .

POLLHUP pada dasarnya berarti bahwa apa yang ada di ujung koneksi telah menutup ujung koneksinya. POSIX mendeskripsikannya sebagai

Perangkat telah terputus. Acara dan POLLOUT ini saling eksklusif; aliran tidak akan pernah dapat ditulis jika hangup telah terjadi.

Ini cukup jelas untuk sebuah terminal:terminal telah hilang (kejadian yang sama yang menghasilkan SIGHUP:sesi modem telah dihentikan, jendela emulator terminal telah ditutup, dll.). POLLHUP tidak pernah dikirim untuk file biasa. Untuk pipa dan soket, tergantung sistem operasinya. Linux menyetel POLLHUP ketika program di ujung tulisan pipa menutup pipa, dan menyetel POLLIN|POLLHUP ketika ujung soket yang lain menutup soket, tetapi POLLIN hanya untuk shutdown soket. *BSD terbaru mengatur POLLIN|POLLUP ketika ujung tulisan pipa menutup pipa, dan perilaku soket lebih bervariasi.


A POLLHUP berarti soket tidak lagi terhubung. Di TCP, ini berarti FIN telah diterima dan dikirim.

A POLLERR berarti soket mendapat kesalahan asinkron. Di TCP, ini biasanya berarti RST telah diterima atau dikirim. Jika deskriptor file bukan soket, POLLERR mungkin berarti perangkat tidak mendukung polling.

Untuk kedua kondisi di atas, deskriptor file soket masih terbuka, dan belum ditutup (tetapi shutdown() mungkin sudah dipanggil). A close() pada deskriptor file akan melepaskan sumber daya yang masih dicadangkan atas nama soket. Secara teori, soket dapat segera digunakan kembali (mis., dengan connect() lain panggilan).

A POLLNVAL berarti deskriptor file soket tidak terbuka. Ini akan menjadi kesalahan untuk close() itu.


Itu tergantung pada sifat kesalahan yang tepat. Gunakan getockopt() untuk melihat masalahnya:

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

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

Cara termudah adalah dengan mengasumsikan bahwa soket tidak lagi dapat digunakan dalam hal apa pun dan menutupnya.


Contoh FIFO minimal

Setelah Anda memahami kapan kondisi tersebut terjadi, seharusnya mudah untuk mengetahui apa yang harus dilakukan dengan kondisi tersebut.

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.

Kompilasi dengan:

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

Penggunaan:

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

Di shell lain:

printf a >poll0.tmp

POLLHUP

Jika Anda tidak mengubah sumbernya:./poll.out keluaran:

loop
POLLIN n=1 buf=a
loop
POLLHUP
loop

Jadi:

  • POLLIN terjadi saat input tersedia
  • POLLHUP terjadi ketika file ditutup oleh printf
  • close(pfd.fd); dan pfd.fd *= -1; bersihkan semuanya, dan kami berhenti menerima POLLHUP
  • poll hang selamanya

Ini adalah operasi normal.

Anda sekarang dapat mengembalikan FIFO untuk menunggu open berikutnya , atau keluar dari loop jika sudah selesai.

POLLNAL

Jika Anda berkomentar pfd.fd *= -1; :./poll.out cetakan:

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

dan berulang selamanya.

Jadi:

  • POLLIN dan POLLHUP dan close terjadi seperti sebelumnya
  • karena kami tidak menyetel pfd.fd ke angka negatif, poll terus mencoba menggunakan fd yang kami tutup
  • ini terus menampilkan POLLNVAL selamanya

Jadi kami melihat bahwa ini seharusnya tidak terjadi, dan menunjukkan adanya bug dalam kode Anda.

POLLERR

Saya tidak tahu cara membuat POLLERR dengan FIFO. Beri tahu saya jika ada jalan. Tapi seharusnya bisa dengan file_operations driver perangkat.

Diuji di Ubuntu 14.04.


Linux
  1. Cara memeriksa Versi OS dan Linux

  2. Cara mengidentifikasi kartu/port HBA dan WWN di Linux

  3. Bagaimana cara memindahkan file dan direktori ke folder induk di Linux?

  1. Bagaimana Linux menyelamatkan komputer yang lambat (dan planet ini)

  2. Cara membuka dan menutup direktori di terminal Linux

  3. Bagaimana menangani perpustakaan dinamis dan statis di Linux

  1. Cara Membuat Alias ​​​​dan Menggunakan Perintah Alias ​​​​di Linux

  2. Cara menemukan ukuran buffer soket linux

  3. Bagaimana saya bisa melihat ukuran file dan direktori di linux?