Уильям Стивенс - UNIX: разработка сетевых приложений
- Название:UNIX: разработка сетевых приложений
- Автор:
- Жанр:
- Издательство:Питер
- Год:2007
- Город:Санкт-Петербург
- ISBN:5-94723-991-4
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Уильям Стивенс - UNIX: разработка сетевых приложений краткое содержание
Новое издание книги, посвященной созданию веб-серверов, клиент-серверных приложений или любого другого сетевого программного обеспечения в операционной системе UNIX, — классическое руководство по сетевым программным интерфейсам, в частности сокетам. Оно основано на трудах Уильяма Стивенса и полностью переработано и обновлено двумя ведущими экспертами по сетевому программированию. В книгу включено описание ключевых современных стандартов, реализаций и методов, она содержит большое количество иллюстрирующих примеров и может использоваться как учебник по программированию в сетях, так и в качестве справочника для опытных программистов.
UNIX: разработка сетевых приложений - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
17 err_sys("nonblocking connect error");
18 fptr->f_flags = F_CONNECTING;
19 FD_SET(fd, &rset); /* включаем дескриптор сокета в наборе чтения
и записи */
20 FD_SET(fd, &wset);
21 if (fd > maxfd)
22 maxfd = fd;
23 } else if (n >= 0) /* соединение уже установлено */
24 write_get_cmd(fptr); /* отправляем команду GET серверу */
25 }
7-13
Мы вызываем нашу функцию host_serv
для поиска и преобразования имени узла и имени службы. Она возвращает указатель на массив структур addrinfo
. Мы используем только первую структуру. Создается сокет TCP, и он становится неблокируемым.
14-22
Вызывается неблокируемая функция connect
, и флагу файла присваивается значение F_CONNECTING
. Включается дескриптор сокета и в наборе чтения, и в наборе записи, поскольку функция select
будет ожидать любого из этих условий как указания на то, что установление соединения завершилось. При необходимости мы также обновляем значение maxfd
.
23-24
Если функция connect
успешно завершается, значит, соединение уже установлено, и функция write_get_cmd
(она показана в следующем листинге) посылает команду серверу.
Мы делаем сокет неблокируемым для функции connect
, но никогда не переустанавливаем его в блокируемый режим, заданный по умолчанию. Это нормально, поскольку мы записываем в сокет только небольшое количество данных (команда GET следующей функции) и считаем, что эти данные занимают значительно меньше места, чем имеется в буфере отправки сокета. Даже если из-за установленного флага отсутствия блокировки при вызове функции write
происходит частичное копирование, наша функция writen
обрабатывает эту ситуацию. Если оставить сокет неблокируемым, это не повлияет на последующее выполнение функций read
, потому что мы всегда вызываем функцию select
для определения того момента, когда сокет станет готов для чтения.
В листинге 16.12 показана функция write_get_cmd
, посылающая серверу команду HTTP GET.
Листинг 16.12. Отправка команды HTTP GET серверу
//nonblock/write_get_cmd.c
1 #include "web.h"
2 void
3 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
.
Теперь мы возвращаемся в функцию main
, показанную в листинге 16.13, начиная с того места, где закончили в листинге 16.9. Это основной цикл программы: пока имеется ненулевое количество файлов для обработки (значение nlefttoread
больше нуля), устанавливается, если это возможно, другое соединение и затем вызывается функция select
для всех активных дескрипторов, обрабатывающая как завершение неблокируемых соединений, так и прием данных.
24-35
Если мы не дошли до заданного предела одновременных соединений и есть дополнительные соединения, которые нужно установить, мы ищем еще не обработанный файл (на него указывает нулевое значение f_flags
) и вызываем функцию start_connect
для инициирования соединения. Число активных соединений увеличивается на единицу ( nconn
), а число соединений, которые нужно установить, на единицу уменьшается ( nlefttoconn
).
36-37
Функция select
ожидает готовности сокета либо для чтения, либо для записи. Дескрипторы, для которых в настоящий момент происходит установление соединения (неблокируемая функция connect
находится в процессе выполнения), будут включены в обоих наборах, в то время как дескрипторы с завершенным соединением, ожидающие данных от сервера, будут включены только в наборе чтения.
Листинг 16.13. Основной цикл функции main
//nonblock/web.c
24 while (nlefttoread > 0) {
25 while (nconn 0) {
26 /* find a file to read */
27 for (i =0; 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
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)
48 error != 0) {
49 err_ret("nonblocking connect failed
50 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 }
67 }
68 }
69 }
70 exit(0);
71 }
39-55
Теперь мы анализируем каждый элемент массива структур file
, чтобы определить, какие дескрипторы нужно обрабатывать. Если установлен флаг F_CONNECTING
и дескриптор включен либо в наборе чтения, либо в наборе записи, неблокируемая функция connect
завершается. Как мы говорили при описании листинга 16.7, мы вызываем функцию getsockopt
, чтобы получить ожидающую обработки ошибку для сокета. Если значение ошибки равно нулю, соединение успешно завершилось. В этом случае мы выключаем дескриптор в наборе флагов записи и вызываем функцию write_get_cmd
для отправки запроса HTTP серверу.
56-67
Если установлен флаг F_READING
и дескриптор готов для чтения, мы вызываем функцию read
. Если соединение было закрыто другим концом, мы закрываем сокет, устанавливаем флаг F_DONE
, выключаем дескриптор в наборе чтения и уменьшаем число активных соединений и общее число соединений, требующих обработки.
Интервал:
Закладка: