Разработка приложений в среде Linux. Второе издание
Шрифт:
25: fds[0].events = POLLIN;
26: fds[1].events = POLLIN;
27:
28: /* пока наблюдаем за одним из fds[0] или fds[1] */
29: while (fds[0].events || fds[1].events ) {
30: if (poll(fds, 2, 0) < 0) {
31: perror("poll");
32: return 1;
33: }
34:
35: /* проверить, какой из файловых дескрипторов
36: готов для чтения из него */
37: for (i = 0; i < 2; i++) {
38: if (fds[i].revents) {
39: /* fds[i] готов для чтения, двигаться дальше... */
40: rc = read(fds[i].fd, buf, sizeof(buf) - 1);
41: if (rc < 0) {
42: perror("read");
43: return 1;
44: } else if (!rc) {
45: /*
этот канал закрыт, не пытаться
46: читать из него снова */
47: fds[i].events = 0;
48: } else {
49: buf[rc] = '\0';
50: printf("чтение : %s", buf);
51: }
52: }
53: }
54: }
55:
56: return 0;
57: }
13.1.3. Мультиплексирование с помощью
select
Системный вызов
poll
был изначально представлен как часть Unix-дерева System V. Усилиями разработчиков BSD та же основная проблема была решена похожим способом — предоставлением системного вызова select
. #include <sys/select.h>
int select(int numfds, fd_set * readfds, fd_set * writefds,
fd_set * exceptfds, struct timeval * timeout);
Три промежуточных параметра —
readfds
, writefds
и exceptfds
— определяют, за какими файловыми дескрипторами необходимо следить. Каждый параметр — это указатель на fd_set
, структуру данных, позволяющую процессу определить произвольное количество файловых дескрипторов [74] . Ею манипулируют с помощью перечисленных ниже макросов.74
Это похоже на тип
sigset_t
, используемый для шаблонов сигналов. FD_ZERO(fd_set * fds); | Очищает fds — в наборе не содержатся файловые дескрипторы. Этот макрос используется для инициализации структур fd_set . |
FD_SET(intfd, fd_set * fds); | Добавляет fd к fd_set . |
FD_CLR(intfd, fd_set * fds); | Удаляет fd из fd_set . |
FD_ISSET(int fd, fd_set * fds); | Возвращает true , если fd содержится в установленном fds . |
Первый набор файловых дескрипторов
select
, readfds
, содержит перечень файловых дескрипторов, вызывающих возврат вызова select
, когда они готовы для чтения [75] или (для каналов и сокетов) когда процесс на другом конце файла закрыл его. Когда любой файловый дескриптор в writefds
готов к записи, select
возвращается, exceptfds
содержит файловые дескрипторы для слежения за исключительными условиями. В Linux (так же, как и в Unix) это происходит только при поступлении внешних данных в сетевое подключение. В качестве любого из них можно указать NULL
, если тот или иной тип события вас не интересует.75
Когда сетевой сокет прослушивается (
listen
) и готов к приему (accept
), считается,
select
; информацию о сокетах можно найти в главе 17. Окончательный параметр,
timeout
, определяет, насколько долго (в миллисекундах) вызову select
необходимо ожидать какого-либо события. Это указывает на struct timeval
, которая выглядит следующим образом. #include <sys/time.h>
struct timeval {
int tv_sec; /* секунды */
int tv_usec; /* микросекунды */
};
Первый элемент —
tv_sec
— это количество оставшихся секунд, a tv_usec
— это количество оставшихся микросекунд. Если значением timeout
является NULL
, select
блокируется до следующего события. Если он указывает на struct timeval
, содержащую 0 в обоих элементах, вызов select
не блокируется. Он обновляет наборы файловых дескрипторов, чтобы определить, какой файловый дескриптор в настоящее время готов для чтения или записи, а затем немедленно возвращается. Первый параметр,
numfds
, вызывает наибольшие трудности. Он задает количество файловых дескрипторов (начиная с файлового дескриптора 0), которое может быть определено с помощью fd_sets
. Еще один (и, возможно, более легкий) способ поведения numfds
намного лучше максимального файлового дескриптора select
[76] . Поскольку Linux обычно позволяет каждому процессу иметь до 1024 файловых дескрипторов,
numfds
избавляет ядро от необходимости просмотра всех 1024 файловых дескрипторов, которые может содержать каждая структура fd_set
, что улучшает показатели производительности.76
Если сравнить это с параметром
numfds
для poll
, то можно понять, почему возникают затруднения. После возврата три структуры
fd_set
содержат файловые дескрипторы с задержкой входных данных, на которые можно произвести запись или которые находятся в исключительном состоянии. Вызов select
в Linux возвращает общее количество элементов, установленных в трех структурах fd_set
, 0
в случае тайм-аута вызова либо – 1
в случае ошибки. Однако многие системы Unix считают определенные файловые дескрипторы в возвращаемом значении только один раз, даже если они находятся как в readfds
, так и в writefds
, поэтому в целях переносимости лучше совершать проверку только тогда, когда возвращаемое значение больше 0
. Если возвращаемое значение равно – 1
, не думайте, что структуры fd_set
остаются незатронутыми. Linux обновляет их только в случае, если select
возвращает значение больше 0, однако некоторые системы Unix демонстрируют иное поведение. Еще одним параметром, связанным с переносимостью, является
timeout
. Ядра Linux [77] обновляют его, чтобы отобразить количество времени, оставшегося до тайм-аута вызова select
, но большинство других систем Unix его не обновляют [78] . Однако другие системы не обновляют тайм-аут с целью соответствия более привычной реализации. Для переносимости устраните зависимость от поведения и явно настройте структуру
timeout
перед вызовом select
.77
Кроме некоторых экспериментальных ядер серии 2.1.
78
Когда Линус Торвальдс впервые реализовал
select
, неспособность ядра BSD обновлять timeout
была отмечена как ошибка на man-странице для select
. Вместо написания ошибочного кода Линус решил "исправить" эту ошибку. К сожалению, комитеты по стандартам одобрили поведение BSD. Поделиться:
Популярные книги
Безымянный раб [Другая редакция]
1. Дорога домой
Фантастика:
боевая фантастика
9.41
рейтинг книги
Измена. Свадьба дракона
Любовные романы:
любовно-фантастические романы
эро литература
5.00
рейтинг книги
Не грози Дубровскому! Том VIII
8. РОС: Не грози Дубровскому!
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Последняя Арена 7
7. Последняя Арена
Фантастика:
рпг
постапокалипсис
5.00
рейтинг книги
На границе империй. Том 9. Часть 3
16. Фортуна дама переменчивая
Фантастика:
космическая фантастика
попаданцы
5.00
рейтинг книги
Все не так, как кажется
Любовные романы:
современные любовные романы
7.70
рейтинг книги
Я же бать, или Как найти мать
Любовные романы:
современные любовные романы
6.44
рейтинг книги
Боярышня Дуняша
1. Боярышня
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Аромат невинности
Любовные романы:
любовно-фантастические романы
эро литература
9.23
рейтинг книги
Кодекс Крови. Книга IХ
9. РОС: Кодекс Крови
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Свет во мраке
8. Изгой
Фантастика:
фэнтези
7.30
рейтинг книги
Приручитель женщин-монстров. Том 3
3. Покемоны? Какие покемоны?
Фантастика:
юмористическое фэнтези
аниме
5.00
рейтинг книги
Жестокая свадьба
Любовные романы:
современные любовные романы
4.87
рейтинг книги
Безродный
1. Игра не для слабых
Фантастика:
боевая фантастика
альтернативная история
6.67