Как обращаться с сокетом Linux, хранящимся в POLLERR, POLLHUP и POLLNVAL?
Мне интересно, что делать, когда опрос устанавливает эти биты? Закрыть сокет, игнорировать или как?
4 ответа
POLLHUP
означает, что сокет больше не подключен. В TCP это означает, что FIN был получен и отправлен.
POLLERR
означает, что сокет получил асинхронную ошибку. В TCP это обычно означает, что RST был получен или отправлен. Если дескриптор файла не является сокетом, POLLERR
может означать, что устройство не поддерживает опрос.
Для обоих условий выше дескриптор файла сокета все еще открыт и еще не был закрыт (но shutdown()
возможно, уже был назван). close()
дескриптор файла высвободит ресурсы, которые все еще зарезервированы от имени сокета. Теоретически, должно быть возможно немедленно повторно использовать сокет (например, с другим connect()
вызов).
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
, Это указывает на то, что read
или же write
вызов вернул бы состояние ошибки (например, ошибка ввода / вывода). Это не включает внеполосные данные, которые select
сигналы через его errorfds
маска но poll
сигналы через POLLPRI
,
POLLHUP
в основном означает, что то, что находится на другом конце соединения, закрыло свой конец соединения. POSIX описывает это как
Устройство было отключено. Это событие и ПРОДАЖА являются взаимоисключающими; поток никогда не может быть доступен для записи, если произошло зависание.
Это достаточно ясно для терминала: терминал ушел (то же самое событие, которое генерирует SIGHUP: сеанс модема был завершен, окно эмулятора терминала было закрыто и т. Д.). POLLHUP
никогда не отправляется для обычного файла. Для труб и розеток это зависит от операционной системы. Наборы Linux POLLHUP
когда программа на конце записи канала закрывает канал и устанавливает POLLIN|POLLHUP
когда другой конец сокета закрыл сокет, но POLLIN
только для отключения розетки. Недавний *BSD набор 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
висит навсегда
Это нормальная операция.
Теперь вы можете вернуть FIFO в ожидании следующего 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
с FIFO. Дайте мне знать, если есть способ. Но это должно быть возможно с file_operations
драйвера устройства.
Проверено в Ubuntu 14.04.