UNIX: разработка сетевых приложений
Часть 187 из 399 Информация о книге
В листинге 16.12 показана функция
, посылающая серверу команду HTTP GET.write_get_cmdЛистинг 16.12. Отправка команды HTTP GET серверу
//nonblock/write_get_cmd.c1 #include "web.h"2 void3 write_get_cmd(struct file *fptr)4 {5 int n;6 char line[MAXLINE];7 n = snprintf(line, sizeof(line), GET_CMD, fptr->f_name);8 Writen(fptr->f_fd, line, n);9 printf("wrote %d bytes for %s\n", n, fptr->f_name);10 fptr->f_flags = F_READING; /* сброс F_CONNECTING */11 FD_SET(fptr->f_fd, &rset); /* прочитаем ответ сервера */12 if (fptr->f_fd > maxfd)13 maxfd = fptr->f_fd;14 }Создание команды и ее отправкаКоманда создается и пишется в сокет.7-9Установка флаговУстанавливается флаг10-13, при этом также сбрасывается флагF_READING(если он установлен). Это указывает основному циклу, что данный дескриптор готов для ввода. Также включается дескриптор в наборе чтения, и при необходимости обновляется значениеF_CONNECTING.maxfdТеперь мы возвращаемся в функцию
, показанную в листинге 16.13, начиная с того места, где закончили в листинге 16.9. Это основной цикл программы: пока имеется ненулевое количество файлов для обработки (значениеmainбольше нуля), устанавливается, если это возможно, другое соединение и затем вызывается функцияnlefttoreadдля всех активных дескрипторов, обрабатывающая как завершение неблокируемых соединений, так и прием данных.selectМожем ли мы инициировать другое соединение?Если мы не дошли до заданного предела одновременных соединений и есть дополнительные соединения, которые нужно установить, мы ищем еще не обработанный файл (на него указывает нулевое значение24-35) и вызываем функциюf_flagsдля инициирования соединения. Число активных соединений увеличивается на единицу (start_connect), а число соединений, которые нужно установить, на единицу уменьшается (nconn).nlefttoconnФункция select: ожидание событийФункция36-37ожидает готовности сокета либо для чтения, либо для записи. Дескрипторы, для которых в настоящий момент происходит установление соединения (неблокируемая функцияselectнаходится в процессе выполнения), будут включены в обоих наборах, в то время как дескрипторы с завершенным соединением, ожидающие данных от сервера, будут включены только в наборе чтения.connectЛистинг 16.13. Основной цикл функции main
//nonblock/web.c24 while (nlefttoread > 0) {25 while (nconn < maxnconn && nlefttoconn > 0) {26 /* find a file to read */27 for (i =0; i < nfiles; i++)28 if (file[i].f_flags == 0)29 break;30 if (i == nfiles)31 err_quit("nlefttoconn = %d but nothing found", nlefttoconn);32 start_connect(&file[i]);33 nconn++;34 nlefttoconn--;35 }36 rs = rset:37 ws = wset;38 n = Select(maxfd + 1, &rs, &ws, NULL, NULL);39 for (i = 0; i < nfiles; i++) {40 flags = file[i].f_flags;41 if (flags == 0 || flags & F_DONE)42 continue;43 fd = file[i].f_fd;44 if (flags & F_CONNECTING &&45 (FD_ISSET(fd, &rs) || FD_ISSET(fd, &ws))) {46 n = sizeof(error);47 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &n) < 0 ||48 error != 0) {49 err_ret("nonblocking connect failed50 for %s", file[i].f_name);51 }52 /* соединение установлено */53 printf("connection established for %s\n", file[i].f_name);54 FD_CLR(fd, &wset); /* отключаем запись в этот сокет */55 write_get_cmd(&file[i]); /* передаем команду GET */56 } else if (flags & F_READING && FD_ISSET(fd, &rs)) {57 if ((n = Read(fd, buf, sizeof(buf))) == 0) {58 printf("end-of-file on %s\n", file[i].f_name);59 Close(fd);60 file[i].f_flags = F_DONE; /* сбрасывает флаг F_READING */61 FD_CLR(fd, &rset);62 nconn--;63 nlefttoread--;64 } else {65 printf("read %d bytes from %s\n", n, file[i].f_name);66 }