UNIX: разработка сетевых приложений
Часть 289 из 399 Информация о книге
26.6. Веб-клиент и одновременное соединение (продолжение)
Вернемся к нашему примеру с веб-клиентом из раздела 16.5 и перепишем его с использованием потоков вместо неблокируемой функции
. Мы можем оставить сокеты в их заданном по умолчанию виде — блокируемыми, и создать один поток на каждое соединение. Каждый поток может блокироваться в вызове функцииconnect, так как ядро будет просто выполнять какой-либо другой поток, готовый к работе.connectВ листинге 26.7 показана первая часть нашей программы, глобальные переменные и начало функции
.mainЛистинг 26.7. Глобальные переменные и начало функции main
//threads/web01.c1 #include "unpthread.h"2 #include <thread.h> /* потоки Solaris */3 #define MAXFILES 204 #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\r\n\r\n"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 int21 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\n", nfiles);36 home_page(argv[2], argv[3]);37 nlefttoread = nlefttoconn = nfiles;38 nconn = 0;Глобальные переменныеМы подключаем заголовочный файл1-16вдобавок к обычному<thread.h>, так как нам требуется использовать потоки Solaris в дополнение к потокам Pthreads, как мы вскоре покажем.<pthread.h>Мы добавили к структуре10один элемент — идентификатор потока ffile. Остальная часть этого кода аналогична коду в листинге 16.9. В этой версии нам не нужно использовать функцию_tid, а следовательно, не нужны наборы дескрипторов и переменнаяselect.maxfdФункция36не изменилась относительно листинга 16.10. В листинге 26.8 показан основной рабочий цикл потока main.home_pageЛистинг 26.8. Основной рабочий цикл потока main
//threads/web01.c39 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\n", tid, fptr->f_name);58 }59 exit(0);60 }По возможности создаем другой потокЕсли имеется возможность создать другой поток (40-52меньше, чемnconn), мы так и делаем. Функция, которую выполняет каждый новый поток, — этоmaxconn, а ее аргументом является указатель на структуруdo_get_read.file