UNIX: разработка сетевых приложений
UNIX: разработка сетевых приложений читать книгу онлайн
Новое издание книги, посвященной созданию веб-серверов, клиент-серверных приложений или любого другого сетевого программного обеспечения в операционной системе UNIX, — классическое руководство по сетевым программным интерфейсам, в частности сокетам. Оно основано на трудах Уильяма Стивенса и полностью переработано и обновлено двумя ведущими экспертами по сетевому программированию. В книгу включено описание ключевых современных стандартов, реализаций и методов, она содержит большое количество иллюстрирующих примеров и может использоваться как учебник по программированию в сетях, так и в качестве справочника для опытных программистов.
Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних чтение данного контента СТРОГО ЗАПРЕЩЕНО! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту [email protected] для удаления материала
Из табл. 30.1 мы видим, что эта простая версия с использованием потоков является более быстродействующей, чем даже самая быстрая из версий с предварительным порождением процессов. Кроме того, эта версия, в которой каждый клиент обслуживается одним потоком, во много раз быстрее версии, в которой каждый клиент обслуживается специально созданным для него дочерним процессом (первая строка табл. 30.1).
В разделе 26.5 мы упомянули о трех вариантах преобразования функции, которая не является безопасной в многопоточной среде, в функцию, обеспечивающую требуемую безопасность. Функция web_child вызывает функцию readline, и версия, показанная в листинге 3.12, не является безопасной в многопоточной среде. На примере, приведенном в листинге 30.20, были испробованы вторая и третья альтернативы из раздела 26.5. Увеличение быстродействия при переходе от альтернативы 3 к альтернативе 2 составило менее одного процента, вероятно, потому, что функция readline использовалась лишь для считывания значения счетчика (5 символов) от клиента. Поэтому в данной главе для простоты мы использовали более медленную версию из листинга 3.11 для сервера с предварительным порождением потоков.
30.11. Сервер TCP с предварительным порождением потоков, каждый из которых вызывает accept
Ранее в этой главе мы обнаружили, что версии, в которых заранее создается пул дочерних процессов, работают быстрее, чем те, в которых для каждого клиентского запроса приходится вызывать функцию
fork
accept
accept
accept
В листинге 30.21 показан заголовочный файл
pthread07.h
Thread
Листинг 30.21. Заголовочный файл pthread07.h
//server/pthread07.h
1 typedef struct {
2 pthread_t thread_tid; /* идентификатор потока */
3 long thread_count; /* количество обработанных запросов */
4 } Thread;
5 Thread *tptr; /* массив структур Thread */
6 int listenfd, nthreads;
7 socklen_t addrlen;
8 pthread_mutex_t mlock;
Мы также объявляем несколько глобальных переменных, таких как дескриптор прослушиваемого сокета и взаимное исключение, которые должны совместно использоваться всеми потоками.
В листинге 30.22 показана функция
main
Листинг 30.22. Функция main для сервера TCP с предварительным порождением потоков
//server/serv07.c
1 #include "unpthread.h"
2 #include "pthread07.h"
3 pthread_mutex_t mlock = PTHREAD_MUTEX_INITIALIZER;
4 int
5 main(int argc, char **argv)
6 {
7 int i;
8 void sig_int(int), thread_make(int);
9 if (argc == 3)
10 listenfd = Tcp_listen(NULL, argv[1], &addrlen);
11 else if (argc == 4)
12 listenfd = Tcp_1isten(argv[1], argv[2], &addrlen);
13 else
14 err_quit("usage: serv07 [ <host> ] <port#> <#threads>");
15 nthreads = atoi(argv[argc - 1]);
16 tptr = Calloc(nthreads, sizeof(Thread));
17 for (i = 0; i < nthreads; i++)
18 thread_make(i); /* завершается только основной поток */
19 Signal(SIGINT, sig_int);
20 for (;;)
21 pause(); /* потоки все выполнили */
22 }
Функции
thread_make
thread_main
Листинг 30.23. Функции thread_make и thread_main
//server/pthread07.c
1 #include "unpthread.h"
2 #include "pthread07.h"
3 void
4 thread_make(int i)
5 {
6 void *thread_main(void*);
7 Pthread_create(&tptr[i].thread_tid, NULL, &thread_main, (void*)i);
8 return; /* завершается основной поток */
9 }
10 void*
11 thread_main(void *arg)
12 {
13 int connfd;
14 void web_child(int);
15 socklen_t clilen;
16 struct sockaddr *cliaddr;
17 cliaddr = Malloc(addrlen);
18 printf("thread %d startingn", (int)arg);
19 for (;;) {
20 clilen = addrlen;
21 Pthread_mutex_lock(&mlock);