-->

UNIX: разработка сетевых приложений

На нашем литературном портале можно бесплатно читать книгу UNIX: разработка сетевых приложений, Стивенс Уильям Ричард-- . Жанр: ОС и Сети. Онлайн библиотека дает возможность прочитать весь текст и даже без регистрации и СМС подтверждения на нашем литературном портале bazaknig.info.
UNIX: разработка сетевых приложений
Название: UNIX: разработка сетевых приложений
Дата добавления: 16 январь 2020
Количество просмотров: 379
Читать онлайн

UNIX: разработка сетевых приложений читать книгу онлайн

UNIX: разработка сетевых приложений - читать бесплатно онлайн , автор Стивенс Уильям Ричард

Новое издание книги, посвященной созданию веб-серверов, клиент-серверных приложений или любого другого сетевого программного обеспечения в операционной системе UNIX, — классическое руководство по сетевым программным интерфейсам, в частности сокетам. Оно основано на трудах Уильяма Стивенса и полностью переработано и обновлено двумя ведущими экспертами по сетевому программированию. В книгу включено описание ключевых современных стандартов, реализаций и методов, она содержит большое количество иллюстрирующих примеров и может использоваться как учебник по программированию в сетях, так и в качестве справочника для опытных программистов.

Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних чтение данного контента СТРОГО ЗАПРЕЩЕНО! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту [email protected] для удаления материала

Перейти на страницу:

22  maxfd = listenfd;

23  cliaddr = Malloc(addrlen);

24  nchildren = atoi(argv[argc - 1]);

25  navail = nchildren;

26  cptr = Calloc(nchildren, sizeof(Child));

27  /* предварительное создание дочерних процессов */

28  for (i = 0; i < nchildren; i++) {

29   child_make(i, listenfd, addrlen); /* родительский процесс

                                          завершается */

30   FD_SET(cptr[i].child_pipefd, &masterset);

31   maxfd = max(maxfd, cptr[i].child_pipefd);

32  }

33  Signal(SIGINT, sig_int);

34  for (;;) {

35   rset = masterset;

36   if (navail <= 0)

37    FD_CLR(listenfd, &rset); /* выключаем, если нет свободных

                                  дочерних процессов */

38   nsel = Select(maxfd + 1, &rset, NULL, NULL, NULL);

39   /* проверка новых соединений */

40   if (FD_ISSET(listenfd, &rset)) {

41    clilen = addrlen;

42    connfd = Accept(listenfd, cliaddr, &clilen);

43    for (i = 0; i < nchildren; i++)

44     if (cptr[i].child_status == 0)

45      break; /* свободный */

46    if (i == nchildren)

47     err_quit("no available children");

48    cptr[i].child_status = 1; /* отмечаем этот дочерний процесс как

                                   занятый */

49    cptr[i].child_count++;

50    navail--;

51    n = Write_fd(cptr[i].child_pipefd, 1, connfd);

52    Close(connfd);

53    if (--nsel == 0)

54     continue; /* с результатами select() закончено */

55   }

56   /* поиск освободившихся дочерних процессов */

57   for (i = 0; i < nchildren; i++) {

58    if (FD_ISSET(cptr[i].child_pipefd, &rset)) {

59     if ((n = Read(cptr[i].child_pipefd, &rc, 1)) == 0)

60      err_quit("child %d terminated unexpectedly", i);

61     cptr[i].child_status = 0;

62     navail++;

63     if (--nsel == 0)

64      break; /* с результатами select() закончено */

65    }

66   }

67  }

68 }

Отключение прослушиваемого сокета в случае отсутствия свободных дочерних процессов

36-37
 Счетчик
navail
отслеживает количество свободных дочерних процессов. Если его значение становится равным нулю, прослушиваемый сокет в наборе дескрипторов функции
select
выключается. Это предотвращает прием нового соединения в тот момент, когда нет ни одного свободного дочернего процесса. Ядро по- прежнему устанавливает эти соединения в очередь, пока их количество не превысит значения аргумента
backlog
функции
listen
, заданного для прослушиваемого сокета, но мы не хотим их принимать, пока у нас не появится свободный дочерний процесс, готовый обрабатывать клиентский запрос.

Прием нового соединения

39-55
 Если прослушиваемый сокет готов для считывания, можно принимать (
accept
) новое соединение. Мы находим первый свободный дочерний процесс и передаем ему присоединенный сокет с помощью функции
write_fd
, приведенной в листинге 15.11. Вместе с дескриптором мы передаем 1 байт, но получатель не интересуется содержимым этого байта. Родитель закрывает присоединенный сокет.

Мы всегда начинаем поиск свободного дочернего процесса с первого элемента массива структур

Child
. Это означает, что новое соединение для обработки поступившего клиентского запроса всегда получает первый элемент этого массива. Этот факт мы проверим при рассмотрении табл. 30.2 и значения счетчика
child_count
после завершения работы сервера. Если мы не хотим оказывать такое предпочтение первому элементу массива, мы можем запомнить, какой дочерний процесс получил последнее клиентское соединение, и каждый раз начинать поиск свободного дочернего процесса со следующего за ним, а по достижении конца массива переходить снова к первому элементу. В этом нет особого смысла (на самом деле все равно, какой дочерний процесс обрабатывает очередное соединение, если имеется несколько свободных дочерних процессов), если только планировочный алгоритм операционной системы не накладывает санкций на процессы, которые требуют относительно больших временных затрат центрального процессора. Более равномерное распределение загрузки между всеми дочерними процессами приведет к выравниванию времен, затраченных на их выполнение.

Обработка вновь освободившихся дочерних процессов

56-66
 Когда дочерний процесс заканчивает обработку клиентского запроса, наша функция
child_main
записывает один байт в канал для родительского процесса. Тем самым родительский конец канала становится доступным для чтения. Упомянутый байт считывается (но его значение при этом игнорируется), а дочерний процесс помечается как свободный. Если же дочерний процесс завершит свое выполнение неожиданно, его конец канала будет закрыт, а операция чтения (
read
) возвратит нулевое значение. Это значение перехватывается и дочерний процесс завершается, но более удачным решением было бы записать ошибку и создать новый дочерний процесс для замены завершенного.

Перейти на страницу:
Комментариев (0)
название