UNIX: разработка сетевых приложений - Страница 64
Три средних аргумента,
readsetwritesetexceptset1. На сокет приходят внеполосные данные. Более подробно мы опишем этот случай в главе 24.
2. Присутствие информации об управлении состоянием (control status information), которая должна быть считана с управляющего (master side) псевдотерминала, помещенного в режим пакетной обработки. Псевдотерминалы в данном томе не рассматриваются.
Проблема в том, как задать одно или несколько значений дескрипторов для каждого из трех аргументов. Функция
selectfd_setvoid FD_ZERO(fd_set *fdset); /* сбрасываем все биты в fdset */void FD_SET(int fd, fd_set *fdset); /* устанавливаем бит для fd в fdset */void FD_CLR(int fd, fd_set *fdset); /* сбрасываем бит для fd в fdset */int FD_ISSET(int fd, fd_set *fdset); /* установлен ли бит для fd в fdset? */Мы размещаем в памяти набор дескрипторов типа
fd_setОписываемый нами массив целых чисел, использующий по одному биту для каждого дескриптора, — это только один из возможных способов реализации функции select. Тем не менее является обычной практикой ссылаться на отдельные дескрипторы в наборе дескрипторов как на биты, например так: «установить бит для прослушиваемого дескриптора в наборе для чтения».
В разделе 6.10 мы увидим, что функция poll использует совершенно другое представление: массив структур переменной длины, по одной структуре для каждого дескриптора.
Например, чтобы определить переменную типа
fd_setfd_set rset;FD_ZERO(&rset); /* инициализируем набор все биты сброшены */FD_SET(1, &rset); /* устанавливаем бит для fd 1 */FD_SET(4, &rset); /* устанавливаем бит для fd 4 */FD_SET(5, &rset); /* устанавливаем бит для fd 5 */Важно инициализировать набор, так как если набор будет создан в виде автоматической переменной и не проинициализировав, результат может оказаться непредсказуемым.
Любой из трех средних аргументов функции
selectreadsetwritesetexceptsetsleeppollsleep_usselectpollАргумент
maxfdp1maxfdp1maxfdp1Константа
FD_SETSIZE<sys/select.h>fd_setmaxfdp1maxfdp1Зачем нужно было включать этот аргумент и вычислять его значение? Причина в том, что он повышает эффективность работы ядра. Хотя каждый набор типа fd_set может содержать множество дескрипторов (обычно до 1024), реальное количество дескрипторов, используемое типичным процессом, значительно меньше. Эффективность возрастает за счет того, что не копируются ненужные части набора дескрипторов между ядром и процессом и не требуется проверять биты, которые всегда являются нулевыми (см. раздел 16.13 [128]).
Функция
selectreadsetwritesetexceptsetfd_setFD_ISSETselectДве наиболее общих ошибки программирования при использовании функции select — это забыть добавить единицу к наибольшему номеру дескриптора и забыть, что наборы дескрипторов имеют тип «значение-результат». Вторая ошибка приводит к тому, что функция select вызывается с нулевым битом в наборе дескрипторов, когда мы думаем, что он установлен в единицу.
Возвращаемое этой функцией значение указывает общее число готовых дескрипторов во всех наборах дескрипторов. Если значение таймера истекает до того, как какой-нибудь из дескрипторов оказывается готов, возвращается нулевое значение. Возвращаемое значение -1 указывает на ошибку (которая может произойти, если, например, выполнение функции прервано перехваченным сигналом).