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

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

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

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

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

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

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

В данном примере для каждого дочернего процесса нам нужна некая структура, содержащая информацию о нем. Заголовочный файл

child.h
, в котором определяется структура
Child
, показан в листинге 30.16.

Листинг 30.16. Структура Child

//server/child.h

1 typedef struct {

2  pid_t child_pid;  /* ID процесса */

3  int child_pipefd; /* программный (неименованный) канал между

                        родительским и дочерним процессами */

4  int child_status; /* 0 = готово */

5  long child_count; /* количество обрабатываемых соединений */

6 } Child;

7 Child *cptr; /* массив структур Child */

Мы записываем идентификатор дочернего процесса, дескриптор программного канала (pipe) родительского процесса, связанного с дочерним, статус дочернего процесса и количество обрабатываемых дочерним процессом клиентских соединений. Это количество выводится обработчиком сигнала

SIGINT
и позволяет нам отслеживать распределение клиентских запросов между дочерними процессами.

Рассмотрим сначала функцию

child_make
, которая приведена в листинге 30.17. Мы создаем канал и доменный сокет Unix (см. главу 14) перед вызовом функции
fork
. После того, как создан дочерний процесс, родительский процесс закрывает один дескриптор (
sockfd[1]
), а дочерний процесс закрывает другой дескриптор (
sockfd[0]
). Более того, дочерний процесс подключает свой дескриптор канала (
sockfd[1]
) к стандартному потоку сообщений об ошибках, так что каждый дочерний процесс просто использует это устройство для связи с родительским процессом. Этот механизм проиллюстрирован схемой, приведенной на рис. 30.3.

Листинг 30.17. Функция child_make: передача дескриптора в сервере с предварительным порождением дочерних процессов

//server/child05.c

 1 #include "unp.h"

 2 #include "child.h"

 3 pid_t

 4 child_make(int i, int listenfd, int addrlen)

 5 {

 6  int sockfd[2];

 7  pid_t pid;

 8  void child_main(int, int, int);

 9  Socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd);

10  if ((pid = Fork()) > 0) {

11   Close(sockfd[1]);

12   cptr[i].child_pid = pid;

13   cptr[i].child_pipefd = sockfd[0];

14   cptr[i].child_status = 0;

15   return (pid); /* родительский процесс */

16  }

17  Dup2(sockfd[1], STDERR_FILENO); /* канал от дочернего процесса к

                                       родительскому */

18  Close(sockfd[0]);

19  Close(sockfd[1]);

20  Close(listenfd); /* дочернему процессу не требуется, чтобы

                        он был открыт */

21  child_main(i, listenfd, addrlen); /* никогда не завершается */

22 }

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

Рис. 30.3. Канал после того, как дочерний и родительский процесс закрыли один конец

После создания всех дочерних процессов мы получаем схему, показанную на рис. 30.4. Мы закрываем прослушиваемый сокет в каждом дочернем процессе, поскольку только родительский процесс вызывает функцию

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

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

Рис. 30.4. Каналы после создания всех дочерних процессов

В листинге 30.18 показана функция

main
. В отличие от предыдущих версий этой функции, в данном случае в памяти размещаются все наборы дескрипторов и в каждом наборе включены все биты, соответствующие прослушиваемому сокету и каналу каждого дочернего процесса. Вычисляется также максимальное значение дескриптора и выделяется память для массива структур
Child
. Основной цикл запускается при вызове функции
select
.

Листинг 30.18. Функция main, использующая передачу дескриптора

//server/serv05.c

 1 #include "unp.h"

 2 #include "child.h"

 3 static int nchildren;

 4 int

 5 main(int argc, char **argv)

 6 {

 7  int listenfd, i, navail, maxfd, nsel, connfd, rc;

 8  void sig_int(int);

 9  pid_t child_make(int, int, int);

10  ssize_t n;

11  fd_set rset, masterset;

12  socklen_t addrlen, clilen;

13  struct sockaddr *cliaddr;

14  if (argc == 3)

15   listenfd = Tcp_listen(NULL, argv[1], &addrlen);

16  else if (argc == 4)

17   listenfd = Tcp_listen(argv[1], argv[2], &addrlen);

18  else

19   err_quit("usage; serv05 [ <host> ] <port#> <#children>");

20  FD_ZERO(&masterset);

21  FD_SET(listenfd, &masterset);

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