Добавить в цитаты Настройки чтения

Страница 185 из 399

Рис. 16.6. Установление первого соединения, а затем множества параллельных соединений

Для дальнейшей оптимизации клиент может начать обработку данных, возвращаемых по первому соединению, до того, как установление первого соединения завершится, и инициировать дополнительные соединения, как только ему станет известно, что они нужны.

Поскольку мы выполняем несколько неблокируемых функций co

Наша программа считывает около 20 строк с веб-сервера. Мы задаем в качестве аргументов командной строки максимальное число параллельных соединений, имя узла сервера, а затем каждое из имен файлов, получаемых с сервера. Типичное выполнение нашей программы выглядит так:

solaris % <b>web % www.foobar.com / image1.gif image2.gif </b>

<b> image3.gif image4.gif image5.gif </b>

<b> image6.gif image7.gif</b>

Аргументы командной строки задают три одновременных соединения, имя узла сервера, имя файла домашней страницы (/ обозначает корневой каталог сервера) и семь файлов, которые затем нужно прочитать (в нашем примере это файлы с изображениями в формате GIF). Обычно на эти семь файлов имеются ссылки с домашней страницы, и чтобы получить их имена, веб-клиент читает домашнюю страницу и обрабатывает код HTML. Чтобы не усложнять этот пример разбором кода HTML, мы просто задаем имена файлов в командной строке.

Это большой пример, поэтому мы будем показывать его частями. В листинге 16.8 представлен наш заголовочный файл web.h, который включен во все файлы.

Листинг 16.8. Заголовок web.h

//nonblock/web.h

 1 #include &quot;unp.h&quot;

 2 #define MAXFILES 20

 3 #define SERV &quot;80&quot; /* номер порта или имя службы */

 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 /* co

11 #define F_READING 2 /* соединение установлено; происходит считывание */

12 #define F_DONE 4 /* все сделано */

13 #define GET_CMD &quot;GET %s HTTP/1.0rnrn&quot;

14 /* глобальные переменные */

15 int nco

16 fd_set rset, wset;

17 /* прототипы функций */

18 void home_page(const char*, const char*);

19 void start_co

20 void write_get_cmd(struct file*);

2-13 Программа считывает некоторое количество (не более MAXFILES) файлов с веб-сервера. Структура file содержит информацию о каждом файле: его имя (копируется из аргумента командной строки), имя узла или IP-адрес сервера, с которого читается файл, дескриптор сокета, используемый для этого файла, и набор флагов, которые указывают, что мы делаем с этим файлом (устанавливаем соединение для получения файла или считываем файл).

14-20 Мы определяем глобальные переменные и прототипы для наших функций, которые мы вскоре опишем.

Листинг 16.9. Первая часть программы одновременного выполнения функций co

//nonblock/web.c

 1 #include &quot;web.h&quot;

 2 int

 3 main(int argc, char **argv)

 4 {

 5  int i, fd, n, maxnco

 6  char buf[MAXLINE];

 7  fd_set rs, ws;

 8  if (argc &lt; 5)

 9   err_quit(&quot;usage: web &lt;#co

10  maxnco

11  nfiles = min(argc - 4, MAXFILES);

12  for (i = 0; i &lt; nfiles; 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(&quot;nfiles = %dn&quot;, nfiles);

18  home_page(argv[2], argv[3]);

19  FD_ZERO(&amp;rset);

20  FD_ZERO(&amp;wset);

21  maxfd = -1;

22  nlefttoread = nlefttoco

23  nco

11-17 Структуры file заполняются соответствующей информацией из аргументов командной строки.

18 Функция home_page, которую мы показываем в следующем листинге, создает соединение TCP, посылает команду серверу и затем читает домашнюю страницу. Это первое соединение, которое выполняется самостоятельно, до того как мы начнем устанавливать параллельные соединения.