Уильям Стивенс - UNIX: разработка сетевых приложений
- Название:UNIX: разработка сетевых приложений
- Автор:
- Жанр:
- Издательство:Питер
- Год:2007
- Город:Санкт-Петербург
- ISBN:5-94723-991-4
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Уильям Стивенс - UNIX: разработка сетевых приложений краткое содержание
Новое издание книги, посвященной созданию веб-серверов, клиент-серверных приложений или любого другого сетевого программного обеспечения в операционной системе UNIX, — классическое руководство по сетевым программным интерфейсам, в частности сокетам. Оно основано на трудах Уильяма Стивенса и полностью переработано и обновлено двумя ведущими экспертами по сетевому программированию. В книгу включено описание ключевых современных стандартов, реализаций и методов, она содержит большое количество иллюстрирующих примеров и может использоваться как учебник по программированию в сетях, так и в качестве справочника для опытных программистов.
UNIX: разработка сетевых приложений - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
После открытия /dev/poll
программа должна инициализировать массив структур pollfd
(тех же, которые используются функцией poll
, но в этом случае поле revents
не используется). Затем массив передается ядру вызовом write
(структура записывается непосредственно в /dev/poll
). После этого программа может вызывать ioctl DP_POLL
и ждать событий. При вызове ioctl
передается следующая структура:
struct dvpoll {
struct pollfd* dp_fds;
int dp_nfds;
int dp_timeout;
};
Поле dp_fds
указывает на буфер, используемый для хранения массива структур pollfd
, возвращаемых вызовом ioctl
. Поле dp_nfds
задает размер буфера. Вызов ioctl
блокируется до появления интересующих программу событий на любом из опрашиваемых дескрипторов, или до прохождения dp_timeout
миллисекунд. При нулевом значении тайм-аута функция ioctl
возвращается немедленно (то есть данный способ может использоваться для реализации неблокируемых сокетов). Тайм-аут, равный -1, означает неопределенно долгое ожидание.
Измененный код функции str_cli
, переписанной из листинга 6.2 с использованием /dev/poll
, приведен в листинге 14.7.
Листинг 14.7. Функция str_cli, использующая /dev/poll
//advio/str_cli_poll03.c
1 #include "unp.h"
2 #include
3 void
4 str_cli(FILE *fp, int sockfd)
5 {
6 int stdineof;
7 char buf[MAXLINE];
8 int n;
9 int wfd;
10 struct pollfd pollfd[2];
11 struct dvpoll dopoll;
12 int i;
13 int result;
14 wfd = Open("/dev/poll", O_RDWR, 0);
15 pollfd[0].fd = fileno(fp);
16 pollfd[0].events = POLLIN;
17 pollfd[0].revents = 0;
18 pollfd[1].fd = sockfd;
19 pollfd[1].events = POLLIN;
20 pollfd[1].revents = 0;
21 Write(wfd, pollfd, sizeof(struct pollfd) * 2);
22 stdineof = 0;
23 for (;;) {
24 /* блокирование до готовности сокета */
25 dopoll.dp_timeout = -1;
26 dopoll.dp_nfds = 2;
27 dopoll.dp_fds = pollfd;
28 result = Ioctl(wfd, DP_POLL, &dopoll);
29 /* цикл по готовым дескрипторам */
30 for (i = 0; i < result; i++) {
31 if (dopoll.dp_fds[i].fd == sockfd) {
32 /* сокет готов к чтению */
33 if ((n = Read(sockfd, buf, MAXLINE)) == 0) {
34 if (stdineof == 1)
35 return; /* нормальное завершение */
36 else
37 err_quit("str_cli: server terminated prematurely");
38 }
39 Write(fileno(stdout), buf, n);
40 } else {
41 /* дескриптор готов к чтению */
42 if ((n = Read(fileno(fp), buf, MAXLINE)) == 0) {
43 stdineof = 1;
44 Shutdown(sockfd, SHUT_WR); /* отправка FIN */
45 continue;
46 }
47 Writen(sockfd, buf, n);
48 }
49 }
50 }
51 }
14-21
Заполнив массив структур pollfd
, мы передаем его в /dev/poll
. В нашем примере используются только два файловых дескриптора, так что мы помещаем их в статический массив. На практике программы, использующие /dev/poll
, обычно следят за сотнями или даже тысячами дескрипторов одновременно, поэтому массив выделяется динамически.
24-28
Программа не вызывает select
, а блокируется в вызове ioctl
в ожидании поступления данных. Возвращаемое значение представляет собой количество готовых к чтению дескрипторов файлов.
30-49
Наша программа относительно проста, потому что мы знаем, что дескрипторов всего два. В большой программе цикл будет более сложным. Возможно даже разделение программы на потоки для обработки данных, полученных по разным дескрипторам.
Интерфейс kqueue
Система FreeBSD версии 4.1 предложила сетевым программистам новый интерфейс, получивший название kqueue
. Этот интерфейс позволяет процессу зарегистрировать фильтр событий, описывающий интересующие данный процесс события kqueue
. К событиям этого типа относятся операции ввода-вывода с файлами и тайм-ауты, а также асинхронный ввод-вывод, уведомление об изменении файлов и обработка сигналов.
#include
#include
#include
int kqueue(void);
int kevent(int kq , const struct kevent * changelist , int nchanges ,
struct kevent * eventlist , int nevents , const struct timespec * timeout );
void EV_SET(struct kevent * kev , uintptr_t ident , short filter ,
u_short flags , u_int fflags , intptr_t data , void * udata );
Функция kqueue
возвращает новый дескриптор kqueue
, который может использоваться в последующих вызовах kevent
. Функция kevent
применяется для регистрации интересующих событий, а также для получения уведомлений об этих событиях. Параметры changelist
и nchanges
описывают изменения в предыдущем варианте списка событий. Если nchanges
отлично от нуля, выполняются все запрошенные в структуре changelist
изменения. Функция kevent
возвращает количество событий или нуль, если произошел выход по тайм-ауту. В аргументе timeout
хранится значение тайм-аута, обрабатываемое подобно тому, как при вызове select
( NULL
для блокирования, ненулевое значение для задания конкретного тайм- аута, а нулевое значение трактуется как необходимость неблокирующего вызова). Обратите внимание, что параметр timeout
имеет тип struct timespec
, отличающийся от struct timeval
в вызове select
тем, что первый имеет наносекундное разрешение, а второй — микросекундное.
Структура kevent
определяется в заголовочном файле :
struct kevent {
uintptr_t ident; /* идентификатор (например, дескриптор файла) */
short filter; /* тип фильтра (например, EVFILT_READ) */
u_short flags; /* флаги действий (например, EV_ADD); */
u_int fflags; /* флаги, относящиеся к конкретным фильтрам */
intptr_t data; /* данные, относящиеся к конкретным фильтрам */
void uidata; /* непрозрачные пользовательские данные */
};
Действия по смене фильтра и флаговые возвращаемые значения приведены в табл. 14.5.
Таблица 14.5. Флаги для операций kevent
Значение flags | Описание | Изменяется | Возвращается |
---|---|---|---|
EV_ADD | Добавить новое событие, подразумевается по умолчанию, если не указан флаг EV_DISABLE | • | |
EV_CLEAR | Сброс состояния события после считывания его пользователем | • | |
EV_DELETE | Удаление события из фильтра | • | |
EV_DISABLE | Отключение события без удаления его из фильтра | • | |
EV_ENABLE | Включение отключенного перед этим события | • | |
EV_ONESHOT | Удаление события после его однократного срабатывания | • | |
EV_EOF | Достигнут конец файла | • | |
EV_ERROR | Произошла ошибка, код errno записан в поле data | • |
Типы фильтров приведены в табл. 14.6.
Таблица 14.6. Типы фильтров
Значение filter | Описание |
---|---|
EVFILT_AIO | События асинхронного ввода-вывода |
EVFILT_PROC | События exit, fork, exec для процесса |
EVFILT_READ | Дескриптор готов для чтения (аналогично select) |
EVFILT_SIGNAL | Описание сигнала |
EVFILT_TIMER | Периодические или одноразовые таймеры |
EVFILT_VNODE | Изменение и удаление файлов |
EVFILT_WRITE | Дескриптор готов для записи (аналогично select) |
Перепишем функцию str_cli
из листинга 6.2 так, чтобы она использовала kqueue
. Результат представлен в листинге 14.8.
Интервал:
Закладка: