Как обрабатывать сокет Linux revents POLLERR, POLLHUP и POLLNVAL?
Мне интересно, что нужно сделать, когда опрос установил эти биты? Закрыть гнездо, игнорировать его или что?
4 ответов
A POLLHUP
означает, что сокет не подключен. В TCP это означает, что FIN был получен и отправлен.
A POLLERR
означает, что сокет получил асинхронную ошибку. В TCP это обычно означает, что RST был получен или отправлен. Если файловый дескриптор не является сокетом,POLLERR
может означать, что устройство не поддерживает опрос.
для обоих вышеуказанных условий дескриптор файла сокета по-прежнему открыт и еще не закрыт (но shutdown()
может уже звонили). А close()
в файловом дескрипторе будут освобождены ресурсы, которые все еще зарезервированы от имени сокета. Теоретически, должно быть возможно немедленно повторно использовать сокет (например, с другим connect()
звонок).
A POLLNVAL
означает, что дескриптор файла сокета не открыт. Было бы ошибкой close()
его.
Это зависит от точного характера ошибки. Используйте getsockopt (), чтобы увидеть проблему:
int error = 0;
socklen_t errlen = sizeof(error);
getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&error, &errlen);
значения:http://www.xinotes.net/notes/note/1793/
самый простой способ-это предположить, что сокет больше не используется в любом случае и закрыть его.
POLLNVAL
означает, что значение дескриптора файла является недопустимым. Это обычно указывает на ошибку в вашей программе, но вы можете положиться на poll
возвращение POLLNVAL
Если вы закрыли файловый дескриптор и с тех пор не открывали ни одного файла, который мог бы повторно использовать дескриптор.
POLLERR
похоже на события ошибки из select
. Это означает, что a read
или write
вызов возвращает состояние ошибки (например, ошибка ввода/вывода). Это не включает в себя внеполосный данные, которые select
сигналы через errorfds
маска, но poll
сигналы через POLLPRI
.
POLLHUP
в основном означает, что на другом конце соединения закрыл свой конец соединения. POSIX описывает его как
устройство было отключено. Это событие и POLLOUT являются взаимоисключающими; поток никогда не может быть записан, если произошло зависание.
это достаточно ясно для терминала: терминал ушел (то же событие, которое генерирует SIGHUP: сеанс модема был прекращен,окно эмулятора терминала было закрыто и т. д.). POLLHUP
никогда не отправляется для обычного файла. Для труб и розеток, это зависит от операционной системы. Наборы для Linux POLLHUP
когда программа на конце записи трубы закрывает трубу и устанавливает POLLIN|POLLHUP
когда другой конец сокета закрыл сокет, но POLLIN
только для выключения сокета. Последние * BSD set POLLIN|POLLUP
когда конец записи трубы закрывает трубу, и поведение для сокетов более изменчиво.
минимальный пример FIFO
как только вы поймете, когда эти условия случаются, надо просто знать, что с ними делать.
#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");
}
}
}
скомпилировать с помощью:
gcc -o poll.out -std=c99 poll.c
использование:
sudo mknod -m 666 poll0.tmp p
./poll.out
на другой снаряд:
printf a >poll0.tmp
POLLHUP
если вы не измените источник: ./poll.out
выходы:
loop
POLLIN n=1 buf=a
loop
POLLHUP
loop
так:
-
POLLIN
происходит когда ввод становится доступным -
POLLHUP
происходит, когда файл закрываетсяprintf
-
close(pfd.fd);
иpfd.fd *= -1;
очистить вещи, и мы перестанем получатьPOLLHUP
-
poll
зависает навсегда
это нормальная работа.
вы теперь могли repoen ФИФО ждать следующего open
, или выход из цикла, если вы сделали.
POLLNAL
если вы прокомментируете pfd.fd *= -1;
: ./poll.out
принты:
POLLIN n=1 buf=a
loop
POLLHUP
loop
POLLNVAL
loop
POLLNVAL
...
и петли навсегда.
так:
-
POLLIN
иPOLLHUP
иclose
произошло перед - так как мы не установили
pfd.fd
отрицательное число,poll
пытается использоватьfd
что мы закрыли - это продолжает возвращаться
POLLNVAL
навсегда
Итак, мы видим, что этого не должно было случиться, и указывает на ошибку в вашем код.
POLLERR
я не знаю, как создать POLLERR
С FIFOs. Дай мне знать, если будет возможность. Но это должно быть возможно с file_operations
драйвера устройства.
протестировано в Ubuntu 14.04.