UNIX: разработка сетевых приложений
Часть 164 из 399 Информация о книге
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 else37 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 }Составление списка дескрипторов для /dev/pollЗаполнив массив структур14-21, мы передаем его вpollfd. В нашем примере используются только два файловых дескриптора, так что мы помещаем их в статический массив. На практике программы, использующие/dev/poll, обычно следят за сотнями или даже тысячами дескрипторов одновременно, поэтому массив выделяется динамически./dev/pollОжидание данныхПрограмма не вызывает24-28, а блокируется в вызовеselectв ожидании поступления данных. Возвращаемое значение представляет собой количество готовых к чтению дескрипторов файлов.ioctlЦикл по дескрипторамНаша программа относительно проста, потому что мы знаем, что дескрипторов всего два. В большой программе цикл будет более сложным. Возможно даже разделение программы на потоки для обработки данных, полученных по разным дескрипторам.30-49Интерфейс kqueue
Система FreeBSD версии 4.1 предложила сетевым программистам новый интерфейс, получивший название
. Этот интерфейс позволяет процессу зарегистрировать фильтр событий, описывающий интересующие данный процесс событияkqueue. К событиям этого типа относятся операции ввода-вывода с файлами и тайм-ауты, а также асинхронный ввод-вывод, уведомление об изменении файлов и обработка сигналов.kqueue#include <sys/types.h>#include <sys/event.h>#include <sys/time.h>int kqueue(void);int kevent(int <i>kq</i>, const struct kevent *<i>changelist</i>, int <i>nchanges</i>,struct kevent *<i>eventlist</i>, int <i>nevents</i>, const struct timespec *<i>timeout</i>);void EV_SET(struct kevent *<i>kev</i>, uintptr_t <i>ident</i>, short <i>filter</i>,u_short <i>flags</i>, u_int <i>fflags</i>, intptr_t <i>data</i>, void *<i>udata</i>);Функция
возвращает новый дескрипторkqueue, который может использоваться в последующих вызовахkqueue. Функцияkeventприменяется для регистрации интересующих событий, а также для получения уведомлений об этих событиях. Параметрыkeventиchangelistописывают изменения в предыдущем варианте списка событий. Еслиnchangesотлично от нуля, выполняются все запрошенные в структуреnchangesизменения. Функцияchangelistвозвращает количество событий или нуль, если произошел выход по тайм-ауту. В аргументеkeventхранится значение тайм-аута, обрабатываемое подобно тому, как при вызовеtimeout(selectдля блокирования, ненулевое значение для задания конкретного тайм- аута, а нулевое значение трактуется как необходимость неблокирующего вызова). Обратите внимание, что параметрNULLимеет типtimeout, отличающийся отstruct timespecв вызовеstruct timevalтем, что первый имеет наносекундное разрешение, а второй — микросекундное.selectСтруктура
определяется в заголовочном файлеkevent:<sys/event.h>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