Уильям Стивенс - UNIX: разработка сетевых приложений
- Название:UNIX: разработка сетевых приложений
- Автор:
- Жанр:
- Издательство:Питер
- Год:2007
- Город:Санкт-Петербург
- ISBN:5-94723-991-4
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Уильям Стивенс - UNIX: разработка сетевых приложений краткое содержание
Новое издание книги, посвященной созданию веб-серверов, клиент-серверных приложений или любого другого сетевого программного обеспечения в операционной системе UNIX, — классическое руководство по сетевым программным интерфейсам, в частности сокетам. Оно основано на трудах Уильяма Стивенса и полностью переработано и обновлено двумя ведущими экспертами по сетевому программированию. В книгу включено описание ключевых современных стандартов, реализаций и методов, она содержит большое количество иллюстрирующих примеров и может использоваться как учебник по программированию в сетях, так и в качестве справочника для опытных программистов.
UNIX: разработка сетевых приложений - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
Константа POLLIN может быть задана путем логического сложения констант POLLRDNORM и POLLRDBAND. Константа POLLIN существовала еще в реализациях SVR3, которые предшествовали полосам приоритета в SVR4, то есть эта константа существует в целях обратной совместимости. Аналогично, константа POLLOUT эквивалентна POLLWRNORM, и первая из них предшествовала второй.
Для сокетов TCP и UDP при описанных условиях функция poll
возвращает указанный флаг revent
. К сожалению, в определении функции poll
стандарта POSIX имеется множество слабых мест (неоднозначностей):
■ Все регулярные данные TCP и все данные UDP считаются обычными.
■ Внеполосные данные TCP (см. главу 24) считаются приоритетными.
■ Когда считывающая половина соединения TCP закрывается (например, если получен сегмент FIN), это также считается равнозначным обычным данным, и последующая операция чтения возвратит нуль.
■ Наличие ошибки для соединения TCP может расцениваться либо как обычные данные, либо как ошибка ( POLLERR
). В любом случае последующая функция read возвращает -1, что сопровождается установкой переменной errno
в соответствующее значение. Это происходит при получении RST или истечении таймера.
■ Информация о доступности нового соединения на прослушиваемом сокете может считаться либо обычными, либо приоритетными данными. В большинстве реализаций эта информация рассматривается как обычные данные.
Число элементов в массиве структур задается аргументом nfds
.
Исторически этот аргумент имел тип long без знака, что является некоторым излишеством. Достаточно будет типа int без знака. В Unix 98 для этого аргумента определяется новый тип — nfds_t.
Аргумент timeout
определяет, как долго функция находится в ожидании перед завершением. Положительным значением задается количество миллисекунд — время ожидания. В табл. 6.3 показаны возможные значения аргумента timeout
.
Таблица 6.3. Значения аргумента timeout для функции poll
Значение аргумента timeout | Описание |
---|---|
INFTIM | Ждать вечно |
0 | Возвращать управление немедленно, без блокирования |
>0 | Ждать в течение указанного числа миллисекунд |
Константа INFTIM
определена как отрицательное значение. Если таймер в данной системе не обеспечивает точность порядка миллисекунд, значение округляется в большую сторону до ближайшего поддерживаемого значения.
POSIX требует, чтобы константа INFTIM была определена в заголовочном файле , но многие системы все еще определяют ее в заголовочном файле .
Как и в случае функции select, любой тайм-аут, установленный для функции poll, ограничивается снизу разрешающей способностью часов в конкретной реализации (обычно 10 мс).
Функция poll
возвращает -1, если произошла ошибка, 0 — если нет готовых дескрипторов до истечения времени таймера, иначе возвращается число дескрипторов с ненулевым элементом revents
.
Если нас больше не интересует конкретный дескриптор, достаточно установить элемент fd
структуры pollfd
равным отрицательному значению. В этом случае элемент events
будет проигнорирован, а элемент revents
при возвращении функции будет сброшен в нуль.
Вспомните наши рассуждения в конце раздела 6.3 относительно константы FD_SETSIZE
и максимального числа дескрипторов в наборе в сравнении с максимальным числом дескрипторов для процесса. У нас не возникает подобных проблем с функцией poll
, поскольку вызывающий процесс отвечает за размещение массива структур pollfd
в памяти и за последующее сообщение ядру числа элементов в массиве. Не существует типа данных фиксированного размера, аналогичного fd_set
, о котором знает ядро.
POSIX требует наличия и функции select, и функции poll. Но если сравнивать их с точки зрения переносимости, то функцию select в настоящее время поддерживает больше систем, чем функцию poll. POSIX определяет также функцию pselect — усовершенствованную версию функции select, которая обеспечивает возможность блокирования сигналов и предоставляет лучшую разрешающую способность по времени, а для функции poll ничего подобного в POSIX нет.
6.11. Эхо-сервер TCP (еще раз)
Теперь мы изменим наш эхо-сервер TCP из раздела 6.8, используя вместо функции select
функцию poll
. В предыдущей версии сервера, работая с функцией select
, мы должны были выделять массив client
вместе с набором дескрипторов rset
(см. рис. 6.12). С помощью функции poll
мы разместим в памяти массив структур pollfd
. В нем же мы будем хранить и информацию о клиенте, не создавая для нее другой массив. Элемент fd
этого массива мы обрабатываем тем же способом, которым обрабатывали массив client
(см. рис. 6.12): значение -1 говорит о том, что элемент не используется, а любое другое значение является номером дескриптора. Вспомните из предыдущего раздела, что любой элемент в массиве структур pollfd
, передаваемый функции poll
с отрицательным значением элемента fd
, просто игнорируется.
В листинге 6.5 показана первая часть кода нашего сервера.
Листинг 6.5. Первая часть сервера TCP, использующего функцию poll
//tcpcliserv/tcpservpoll01.с
1 #include "unp.h"
2 #include <1imits.h> /* для OPEN_MAX */
3 int
4 main(int argc, char **argv)
5 {
6 int i, maxi, listenfd, connfd, sockfd;
7 int nready;
8 ssize_t n;
9 char buf[MAXLINE];
10 socklen_t clilen;
11 struct pollfd client[OPEN_MAX];
12 struct sockaddr_in cliaddr, servaddr;
13 listenfd = Socket(AF_INET, SOCK_STREAM, 0);
14 bzero(&servaddr, sizeof(servaddr));
15 servaddr.sin_family = AF_INET;
16 servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
17 servaddr.sin_port = htons(SERV_PORT);
18 Bind(listenfd, (SA*)&servaddr, sizeof(servaddr));
19 Listen(listenfd, LISTENQ);
20 client[0].fd = listenfd;
21 client[0].events = POLLRDNORM;
22 for (i = 1; i < OPEN_MAX; i++)
23 client[i].fd = -1; /* -1 означает, что элемент свободен */
24 maxi = 0; /* максимальный индекс массива client[] */
11
Мы объявляем массив структур pollfd
размером OPEN_MAX
. Не существует простого способа определить максимальное число дескрипторов, которые могут быть открыты процессом. Мы снова столкнемся с этой проблемой в листинге 13.1. Один из способов ее решения — вызвать функцию POSIX sysconf
с аргументом _SC_OPEN_MAX
[110, с. 42-44], а затем динамически выделять в памяти место для массива соответствующего размера. Однако функция sysconf
может возвратить некое «неопределенное» значение, и в этом случае нам придется задавать ограничение самим. Здесь мы используем только константу OPEN_MAX
стандарта POSIX.
20-24
Мы используем первый элемент в массиве client
для прослушиваемого сокета и присваиваем дескрипторам для оставшихся элементов -1. Мы также задаем в качестве аргумента функции poll
событие POLLRDNORM
, чтобы получить уведомление от этой функции в том случае, когда новое соединение будет готово к приему. Переменная maxi
содержит максимальный индекс массива client
, используемый в настоящий момент.
Интервал:
Закладка: