26.6. Веб-клиент и одновременное соединение (продолжение)

26.6. Веб-клиент и одновременное соединение (продолжение)

Вернемся к нашему примеру с веб-клиентом из раздела 16.5 и перепишем его с использованием потоков вместо неблокируемой функции connect. Мы можем оставить сокеты в их заданном по умолчанию виде — блокируемыми, и создать один поток на каждое соединение. Каждый поток может блокироваться в вызове функции connect, так как ядро будет просто выполнять какой-либо другой поток, готовый к работе.

В листинге 26.7 показана первая часть нашей программы, глобальные переменные и начало функции main.

Листинг 26.7. Глобальные переменные и начало функции main

//threads/web01.c

 1 #include "unpthread.h"

 2 #include <thread.h> /* потоки Solaris */

 3 #define MAXFILES 20

 4 #define SERV    "80" /* номер порта или имя службы */

 5 struct file {

 6  char      *f_name; /* имя файла */

 7  char      *f_host; /* имя узла или IP-адрес */

 8  int       f_fd;    /* дескриптор */

 9  int       f_flags; /* F_xxx ниже */

10  pthread_t f_tid;   /* идентификатор потока */

11 } file[MAXFILES];

12 #define F_CONNECTING 1 /* функция connect () в процессе

                             выполнения */

13 #define F_READING 2    /* функция connect() завершена;

                             выполняется считывание */

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

15 #define GET_CMD "GET %s HTTP/1.0 "

16 int nconn, nfiles, nlefttoconn, nlefttoread;

17 void *do_get_read(void*);

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

19 void write_get_cmd(struct file*);

20 int

21 main(int argc, char **argv)

22 {

23  int i, n, maxnconn;

24  pthread_t tid;

25  struct file *fptr;

26  if (argc < 5)

27   err_quit("usage: web <#conns> <IPaddr> <homepage> file1 ...");

28  maxnconn = atoi(argv[1]);

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

30  for (i = 0; i < nfiles; i++) {

31   file[i].f_name = argv[i + 4];

32   file[i].f_host = argv[2];

33   file[i].f_flags = 0;

34  }

35  printf("nfiles = %d ", nfiles);

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

37  nlefttoread = nlefttoconn = nfiles;

38  nconn = 0;

Глобальные переменные

1-16 Мы подключаем заголовочный файл <thread.h> вдобавок к обычному <pthread.h>, так как нам требуется использовать потоки Solaris в дополнение к потокам Pthreads, как мы вскоре покажем.

10 Мы добавили к структуре file один элемент — идентификатор потока f_tid. Остальная часть этого кода аналогична коду в листинге 16.9. В этой версии нам не нужно использовать функцию select, а следовательно, не нужны наборы дескрипторов и переменная maxfd.

36 Функция home_page не изменилась относительно листинга 16.10. В листинге 26.8 показан основной рабочий цикл потока main.

Листинг 26.8. Основной рабочий цикл потока main

//threads/web01.c

39  while (nlefttoread > 0) {

40   while (nconn < maxnconn && nlefttoconn > 0) {

41    /* находим файл для считывания */

42    for (i = 0; i < nfiles; i++)

43     if (file[i].f_flags == 0)

44      break;

45    if (i == nfiles)

46     err_quit("nlefttoconn = %d but nothing found", nlefttoconn);

47    file[i].f_flags = F_CONNECTING;

48    Pthread_create(&tid, NULL, &do_get_read, &file[i]);

49    file[i].f_tid = tid;

50    nconn++;

51    nlefttoconn--;

52   }

53   if ((n = thr_join(0, &tid, (void**)&fptr)) != 0)

54    errno = n, err_sys("thr_join error");

55   nconn--;

56   nlefttoread--;

57   printf("thread id %d for %s done ", tid, fptr->f_name);

58  }

59  exit(0);

60 }

По возможности создаем другой поток

40-52 Если имеется возможность создать другой поток (nconn меньше, чем maxconn), мы так и делаем. Функция, которую выполняет каждый новый поток, — это do_get_read, а ее аргументом является указатель на структуру file.

Ждем, когда завершится выполнение какого-либо потока

53-54 Мы вызываем функцию потоков thr_join Solaris с нулевым первым аргументом, чтобы дождаться завершения выполнения какого-либо из наших потоков. К сожалению, в Pthreads не предусмотрен способ, с помощью которого мы могли бы ждать завершения выполнения любого потока, и функция pthread_join требует, чтобы мы точно указали, завершения какого потока мы ждем. В разделе 26.9 мы увидим, что решение этой проблемы в случае применения технологии Pthreads оказывается сложнее и требует использования условной переменной для сообщения главному потоку о завершении выполнения дополнительного потока.

ПРИМЕЧАНИЕ

Показанное здесь решение, в котором используется функция потоков thr_join Solaris, не является, вообще говоря, совместимым со всеми системами. Тем не менее мы приводим здесь эту версию веб-клиента, использующую потоки, чтобы не осложнять обсуждение рассмотрением условных переменных и взаимных исключений (mutex). К счастью, в Solaris допустимо смешивать потоки Pthreads и потоки Solaris.

В листинге 26.9 показана функция do_get_read, которая выполняется каждым потоком. Эта функция устанавливает соединение TCP, посылает серверу команду HTTP GET и считывает ответ сервера.

Листинг 26.9. Функция do_get_read

//threads/web01.c

61 void*

62 do_get_read(void *vptr)

63 {

64  int fd, n;

65  char line[MAXLINE];

66  struct file *fptr;

67  fptr = (struct file*)vptr;

68  fd = Tcp_connect(fptr->f_host, SERV);

69  fptr->f_fd = fd;

70  printf("do_get_read for %s, fd %d, thread %d ",

71   fptr->f_name, fd, fptr->f_tid);

72  write_get_cmd(fptr);

73  /* Чтение ответа сервера */

74  for (;;) {

75   if ((n = Read(fd, line, MAXLINE)) == 0)

76    break; /* сервер закрывает соединение */

77   printf ("read %d bytes from %s ", n, fptr->f_name);

78  }

79  printf("end-of-file on %s ", fptr->f_name);

80  Close(fd);

81  fptr->f_flags = F_DONE; /* сбрасываем F_READING */

82  return (fptr); /* завершение потока */

83 }

Создание сокета TCP, установление соединения

68-71 Создается сокет TCP, и с помощью функции tcp_connect устанавливается соединение. В данном случае используется обычный блокируемый сокет, поэтому поток будет блокирован при вызове функции connect, пока не будет установлено соединение.

Отправка запроса серверу

72 Функция write_get_cmd формирует команду HTTP GET и отсылает ее серверу. Мы не показываем эту функцию заново, так как единственным отличием от листинга 16.12 является то, что в версии, использующей потоки, не вызывается макрос FD_SET и не используется maxfd.

Чтение ответа сервера

73-82 Затем считывается ответ сервера. Когда соединение закрывается сервером, устанавливается флаг F_DONE и функция возвращает управление, завершая выполнение потока.

Мы также не показываем функцию home_page, так как она полностью повторяет версию, приведенную в листинге 16.10.

Мы вернемся к этому примеру, заменив функцию Solaris thr_join на более переносимую функцию семейства Pthreads, но сначала нам необходимо обсудить взаимные исключения и условные переменные.

Поделитесь на страничке

Следующая глава >

Похожие главы из других книг

2.1. Модемное соединение

Из книги Fedora 8 Руководство пользователя автора Колисниченко Денис Николаевич

2.1. Модемное соединение 2.1.1. Выбор модема Модем модему рознь. Модемы различаются по разным признакам, но главные из них - это способ подключения к компьютеру и организация взаимодействия с ним.Модем может подключаться или к СОМ-порту или к шине USB. Раньше у Linux были проблемы


2.2. ADSL-соединение

Из книги Визуальное моделирование электронных схем в PSPICE автора Хайнеманн Роберт

2.2. ADSL-соединение 2.2.1. Преимущества ADSL-соединения В последнее время очень популярны ADSL-соединения (Asymmetric Digital Subscriber Line, асимметричная цифровая абонентская линия), Причина их популярности проста: высокая скорость и дешевизна, Как правило, в месяц безлимитное ADSL-соединение


6.3. Одновременное изображение диаграмм в отдельных системах координат

Из книги Разработка приложений в среде Linux. Второе издание автора Джонсон Майкл К.

6.3. Одновременное изображение диаграмм в отдельных системах координат На рис. 6.8 в одной системе координат изображены четыре диаграммы. Этот метод подходит для двух или даже трех диаграмм, однако, если требуется большее количество, то ориентироваться в них становится


17.4.3. Соединение с сервером

Из книги VBA для чайников автора Каммингс Стив

17.4.3. Соединение с сервером Процесс соединения с сервером через сокет домена Unix состоит из создания сокета и присоединения к требуемому адресу через функцию connect(). Как только сокет присоединен, он может обрабатываться как любой другой файловый дескриптор.Следующая


Одновременное форматирование нескольких элементов управления

Из книги Программирование КПК и смартфонов на .NET Compact Framework автора Климов Александр П.

Одновременное форматирование нескольких элементов управления Многие команды меню Format предназначены для работы сразу с несколькими элементами управления или с несколькими группами элементов управления. Все эти команды будут обсуждаться в данном разделе, но сначала


Инфракрасное соединение

Из книги Бесплатные разговоры через Интернет автора Фрузоров Сергей

Инфракрасное соединение Несмотря на растущую популярность Wi-Fi, Bluetooth и других беспроводных технологий, по-прежнему не сдает своих позиций и передача данных через инфракрасный порт. Например, все мы каждый день применяем инфракрасный порт при использовании


Разовое соединение

Из книги Наглядный самоучитель работы на нетбуке автора Сенкевич Г. Е.

Разовое соединение Совершенно не обязательно вносить новое соединение в свою записную книжку, если вам надо подключиться к удаленному компьютеру только один раз. Для этого используется разовое соединение, которое доступно через меню Соединение | Соединение с (рис. 8.9).


Как разорвать соединение?

Из книги Первые шаги с Windows 7. Руководство для начинающих автора Колисниченко Денис Н.

Как разорвать соединение? Соединение с Интернетом через мобильный телефон — коммутируемое. Другими словами, каждый раз, когда вам понадобится выход во Всемирную сеть, его следует включать, а когда доступ уже не требуется — выключать (разрывать). Отключиться от Интернета


6.1. Модемное соединение

Из книги Firebird РУКОВОДСТВО РАЗРАБОТЧИКА БАЗ ДАННЫХ автора Борри Хелен

6.1. Модемное соединение К Интернету можно подключиться разными способами. Один из наиболее часто используемых — удаленное соединение по коммутируемым сетям общего пользования через модем, выполняющий модуляцию и демодуляцию (отсюда и название) дискретных сигналов.


6.3. Оптимальное: DSL-соединение

Из книги Искусство программирования на языке сценариев командной оболочки автора Купер Мендель

6.3. Оптимальное: DSL-соединение DSL (Digital Subscriber Line) — цифровая абонентская линия, позволяющая производить двунаправленный обмен данными по телефонной линии. Существует несколько вариантов DSL-линий: ADSL, VDSL, SDSL, RADSL. Наиболее распространены ADSL-линии. ADSL (Asymmetric DSL) —


Внутреннее соединение

Из книги IT-безопасность: стоит ли рисковать корпорацией? автора Маккарти Линда

Внутреннее соединение Следующий оператор соединяет две таблицы, которые связаны через внешний ключ FK правой таблицы (Table2) и первичный ключ PK таблицы Table1:SELECTТаblе1.PK,Table1.COL1,Table2.PKX,Table2.COLXFROM Table1 INNER JOIN Table2ON Table1.PK = Table2.FKWHERE... условия-поискаЭто спецификация внутреннего


Пример 16-3. Одновременное перенаправление устройств, stdin и stdout, с помощью команды exec

Из книги автора

Пример 16-3. Одновременное перенаправление устройств, stdin и stdout, с помощью команды exec #!/bin/bash# upperconv.sh# Преобразование символов во входном файле в верхний регистр.E_FILE_ACCESS=70E_WRONG_ARGS=71if [ ! -r "$1" ] # Файл доступен для чтения?then echo "Невозможно прочитать из заданного файла!" echo


Соединение с партнерами

Из книги автора

Соединение с партнерами Компания JFC Farmaceutical захотела предоставить доступ к своей информации одному из своих клиентов для ускорения совместного исследовательского проекта. Клиенту, компании McConnell Drugs, был нужен доступ к информации, хранящейся на сервере базы данных (Drug10).


4.8. Этап 3: нажатие кнопки затвора и одновременное срабатывание системы автоматической фокусировки

Из книги автора

4.8. Этап 3: нажатие кнопки затвора и одновременное срабатывание системы автоматической фокусировки Режимы протяжки Цифровым камерам (правда, не всем) доступно несколько режимов съемки, аналогичных тем, которые в традиционной фотографии называются режимами протяжки