UNIX: разработка сетевых приложений
Часть 165 из 399 Информация о книге
Значение 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) Перепишем функцию
из листинга 6.2 так, чтобы она использовалаstr_cli. Результат представлен в листинге 14.8.kqueueЛистинг 14.8. Функция str_cli, использующая kqueue
//advio/str_cli_kqueue04.c1 #include "unp.h"2 void3 str_cli(FILE *fp, int sockfd)4 {5 int kq, i, n, nev, stdineof = 0, isfile;6 char buf[MAXLINE];7 struct kevent kev[2];8 struct timespec ts;9 struct stat st;10 isfile = ((fstat(fileno(fp), &st) 0) &&11 (st.st_mode & S_IFMT) == S_IFREG);12 EV_SET(&kev[0], fileno(fp), EVFILT_READ, EV_ADD, 0, 0, NULL);13 EV_SET(&kev[1], sockfd, EVFILT_READ, EV_ADD, 0, 0, NULL);14 kq = Kqueue();15 ts.tv_sec = ts.tv_nsec = 0;16 Kevent(kq, kev, 2, NULL, 0, &ts);17 for (;;) {18 nev = Kevent(kq, NULL, 0, kev, 2, NULL);19 for (i = 0; i < nev; i++) {20 if (kev[i].ident == sockfd) { /* сокет готов для чтения */21 if ((n = Read(sockfd, buf, MAXLINE)) == 0) {22 if (stdineof == 1)23 return; /* нормальное завершение*/24 else25 err_quit("str_cli: server terminated prematurely");26 }27 Write(fileno(stdout), buf, n);28 }29 if (kev[i].ident == fileno(fp)) { /* входной поток готов к чтению */30 n = Read(fileno(fp), buf, MAXLINE);31 if (n > 0)32 Writen(sockfd, buf, n);33 if (n == 0 || (isfile && n == kev[i].data)) {34 stdineof = 1;35 Shutdown(sockfd, SHUT_WR); /* отправка FIN */36 kev[i].flags = EV_DELETE;37 Kevent(kq, &kev[i], 1, NULL, 0, &ts); /* удалениеkevent */38 continue;39 }40 }41 }42 }43 }Проверка, указывает ли дескриптор на файлПоведение10-11при достижении конца файла зависит от того, связан ли данный дескриптор с файлом, каналом или терминалом, поэтому мы вызываемkqueue, чтобы убедиться, что мы работаем с файлом. Эти сведения понадобятся позже.fstatНастройка структур kevent для kqueueПри помощи макроса12-13мы настраиваем две структурыEV_SET. Обе содержат фильтр событий готовности к чтению (kevent) и запрос на добавление этого события к фильтру (EVFILT_READ).EV_ADD