Уильям Стивенс - UNIX: разработка сетевых приложений
- Название:UNIX: разработка сетевых приложений
- Автор:
- Жанр:
- Издательство:Питер
- Год:2007
- Город:Санкт-Петербург
- ISBN:5-94723-991-4
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Уильям Стивенс - UNIX: разработка сетевых приложений краткое содержание
Новое издание книги, посвященной созданию веб-серверов, клиент-серверных приложений или любого другого сетевого программного обеспечения в операционной системе UNIX, — классическое руководство по сетевым программным интерфейсам, в частности сокетам. Оно основано на трудах Уильяма Стивенса и полностью переработано и обновлено двумя ведущими экспертами по сетевому программированию. В книгу включено описание ключевых современных стандартов, реализаций и методов, она содержит большое количество иллюстрирующих примеров и может использоваться как учебник по программированию в сетях, так и в качестве справочника для опытных программистов.
UNIX: разработка сетевых приложений - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
Для дальнейшей оптимизации клиент может начать обработку данных, возвращаемых по первому соединению, до того, как установление первого соединения завершится, и инициировать дополнительные соединения, как только ему станет известно, что они нужны.
Поскольку мы выполняем несколько неблокируемых функций connect
одновременно, мы не можем использовать нашу функцию connect_nonb
, показанную в листинге 16.7, так как она не завершается, пока соединение не установлено. Вместо этого мы отслеживаем множество соединений самостоятельно.
Наша программа считывает около 20 строк с веб-сервера. Мы задаем в качестве аргументов командной строки максимальное число параллельных соединений, имя узла сервера, а затем каждое из имен файлов, получаемых с сервера. Типичное выполнение нашей программы выглядит так:
solaris % web % www.foobar.com / image1.gif image2.gif \
image3.gif image4.gif image5.gif \
image6.gif image7.gif
Аргументы командной строки задают три одновременных соединения, имя узла сервера, имя файла домашней страницы ( /
обозначает корневой каталог сервера) и семь файлов, которые затем нужно прочитать (в нашем примере это файлы с изображениями в формате GIF). Обычно на эти семь файлов имеются ссылки с домашней страницы, и чтобы получить их имена, веб-клиент читает домашнюю страницу и обрабатывает код HTML. Чтобы не усложнять этот пример разбором кода HTML, мы просто задаем имена файлов в командной строке.
Это большой пример, поэтому мы будем показывать его частями. В листинге 16.8 представлен наш заголовочный файл web.h
, который включен во все файлы.
Листинг 16.8. Заголовок web.h
//nonblock/web.h
1 #include "unp.h"
2 #define MAXFILES 20
3 #define SERV "80" /* номер порта или имя службы */
4 struct file {
5 char *f_name; /* имя файла */
6 char *f_host; /* имя узла или адрес IPv4/IPv6 */
7 int f_fd; /* дескриптор */
8 int f_flags; /* F_xxx определены ниже */
9 } file[MAXFILES];
10 #define F_CONNECTING 1 /* connect() в процессе выполнения */
11 #define F_READING 2 /* соединение установлено; происходит считывание */
12 #define F_DONE 4 /* все сделано */
13 #define GET_CMD "GET %s HTTP/1.0\r\n\r\n"
14 /* глобальные переменные */
15 int nconn, nfiles, nlefttoconn, nlefttoread, maxfd;
16 fd_set rset, wset;
17 /* прототипы функций */
18 void home_page(const char*, const char*);
19 void start_connect (struct file*);
20 void write_get_cmd(struct file*);
2-13
Программа считывает некоторое количество (не более MAXFILES
) файлов с веб-сервера. Структура file
содержит информацию о каждом файле: его имя (копируется из аргумента командной строки), имя узла или IP-адрес сервера, с которого читается файл, дескриптор сокета, используемый для этого файла, и набор флагов, которые указывают, что мы делаем с этим файлом (устанавливаем соединение для получения файла или считываем файл).
14-20
Мы определяем глобальные переменные и прототипы для наших функций, которые мы вскоре опишем.
Листинг 16.9. Первая часть программы одновременного выполнения функций connect: глобальные переменные и начало функции main
//nonblock/web.c
1 #include "web.h"
2 int
3 main(int argc, char **argv)
4 {
5 int i, fd, n, maxnconn, flags, error;
6 char buf[MAXLINE];
7 fd_set rs, ws;
8 if (argc < 5)
9 err_quit("usage: web ...");
10 maxnconn = atoi(argv[1]);
11 nfiles = min(argc - 4, MAXFILES);
12 for (i = 0; i
13 file[i].f_name = argv[i + 4];
14 file[i].f_host = argv[2];
15 file[i].f_flags = 0;
16 }
17 printf("nfiles = %d\n", nfiles);
18 home_page(argv[2], argv[3]);
19 FD_ZERO(&rset);
20 FD_ZERO(&wset);
21 maxfd = -1;
22 nlefttoread = nlefttoconn = nfiles;
23 nconn = 0;
11-17
Структуры file
заполняются соответствующей информацией из аргументов командной строки.
18
Функция home_page
, которую мы показываем в следующем листинге, создает соединение TCP, посылает команду серверу и затем читает домашнюю страницу. Это первое соединение, которое выполняется самостоятельно, до того как мы начнем устанавливать параллельные соединения.
19-23
Инициализируются два набора дескрипторов, по одному для чтения и для записи. maxfd
— это максимальный дескриптор для функции select
(который мы инициализируем значением -1, поскольку дескрипторы неотрицательны), nlefttoread
— число файлов, которые осталось прочитать (когда это значение становится нулевым, чтение заканчивается), nlefttoconn
— это количество файлов, для которых пока еще требуется соединение TCP, a nconn
— это число соединений, открытых в настоящий момент (оно никогда не может превышать первый аргумент командной строки).
В листинге 16.10 показана функция home_page
, вызываемая один раз, когда начинается выполнение функции main.
Листинг 16.10. Функция home_page
//nonblock/home_page.c
1 #include "web.h"
2 void
3 home_page(const char *host, const char *fname)
4 {
5 int fd, n;
6 char line[MAXLINE];
7 fd = Tcp_connect(host, SERV); /* блокируемая функция connect() */
8 n = snprintf(line, sizeof(line), GET_CMD, fname);
9 Writen(fd, line, n);
10 for (;;) {
11 if ((n = Read(fd, line, MAXLINE)) == 0)
12 break; /* сервер закрыл соединение */
13 printf("read %d bytes of home page\n", n);
14 /* обрабатываем полученные данные */
15 }
16 printf("end-of-file on home page\n");
17 Close(fd);
18 }
7
Наша функция tcp_connect
устанавливает соединение с сервером.
8-17
Запускается команда HTTP GET
для домашней страницы (часто обозначается символом /
). Читается ответ (с ответом мы в данном случае ничего не делаем), и соединение закрывается.
Следующая функция, start_connect
, показанная в листинге 16.11, инициирует вызов неблокируемой функции connect.
Листинг 16.11. Инициирование неблокируемой функции connect
//nonblock/start_connect.c
1 #include "web.h"
2 void
3 start_connect(struct file *fptr)
4 {
5 int fd, flags, n;
6 struct addrinfo *ai;
7 ai = Host_serv(fptr->f_host, SERV, 0, SOCK_STREAM);
8 fd = Socket(ai->ai_family; ai->ai_socktype, ai->ai_protocol);
9 fptr->f_fd = fd;
10 printf("start_connect for %s, fd %d\n", fptr->f_name, fd);
11 /* отключаем блокирование сокета */
12 flags = Fcntl(fd, F_GETFL, 0);
13 Fcntl(fd, F_SETFL, flags | O_NONBLOCK);
14 /* инициируем неблокируемое соединение с сервером */
15 if ((n = connected, ai->ai_addr, ai->ai_addrlen))
16 if (errno != EINPROGRESS)
Интервал:
Закладка: