Вход/Регистрация
UNIX: разработка сетевых приложений
вернуться

Стивенс Уильям Ричард

Шрифт:

Если у процесса, вызывающего функцию

wait
, нет завершенных дочерних процессов, но есть один или несколько выполняющихся, функция
wait
блокируется до тех пор, пока первый из дочерних процессов не завершится.

Функция

waitpid
предоставляет более гибкие возможности выбора ожидаемого процесса и его блокирования. Прежде всего, в аргументе
pid
задается идентификатор процесса, который мы будем ожидать. Значение -1 говорит о том, что нужно дождаться завершения первого дочернего процесса. (Существуют и другие значения идентификаторов процесса, но здесь они нам не понадобятся.) Аргумент
options
позволяет задавать дополнительные параметры. Наиболее общеупотребительным является параметр
WNOHANG
: он сообщает ядру, что не нужно выполнять блокирование, если нет завершенных дочерних процессов.

Различия между функциями wait и waitpid

Теперь мы проиллюстрируем разницу между функциями

wait
и
waitpid
, используемыми для сброса завершенных дочерних процессов. Для этого мы изменим код нашего клиента TCP так, как показано в листинге 5.7. Клиент устанавливает пять соединений с сервером, а затем использует первое из них (
sockfd[0]
) в вызове функции
str_cli
. Несколько соединений мы устанавливаем для того, чтобы породить от параллельного сервера множество дочерних процессов, как показано на рис. 5.2.

Рис. 5.2. Клиент, установивший пять соединений с одним и тем же параллельным сервером

Листинг 5.7. Клиент TCP, устанавливающий пять соединений с сервером

/

/tcpcliserv/tcpcli04.c

1 #include "unp.h"

2 int

3 main(int argc, char **argv)

4 {

5 int i, sockfd[5];

6 struct sockaddr_in servaddr;

7 if (argc != 2)

8 err_quit("usage: tcpcli <Ipaddress>");

9 for (i = 0; i < 5; i++) {

10 sockfd[i] = Socket(AF_INET, SOCK_STREAM, 0);

11 bzero(&servaddr, sizeof(servaddr));

12 servaddr.sin_family = AF_INET;

13 servaddr.sin_port = htons(SERV_PORT);

14 Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);

15 Connect(sockfd[i], (SA*)&servaddr, sizeof(servaddr));

16 }

17 str_cli(stdin, sockfd[0]); /* эта функция выполняет все необходимые

действия для формирования запроса клиента */

18 exit(0);

19 }

Когда клиент завершает работу, все открытые дескрипторы автоматически закрываются ядром (мы не вызываем функцию close

,
а пользуемся только функцией
exit
) и все пять соединений завершаются приблизительно в одно и то же время. Это вызывает отправку пяти сегментов FIN, по одному на каждое соединение, что, в свою очередь, вызывает примерно одновременное завершение всех пяти дочерних процессов. Это приводит к доставке пяти сигналов
SIGCHLD
практически в один и тот же момент, что показано на рис. 5.3.

Доставка множества экземпляров одного и того же сигнала вызывает проблему, к рассмотрению которой мы и приступим.

Рис. 5.3. Клиент завершает работу, закрывая все пять соединений и завершая все пять дочерних процессов

Сначала мы запускаем сервер в фоновом режиме, а затем — новый клиент. Наш сервер, показанный в листинге 5.1, несколько модифицирован — теперь в нем вызывается функция

signal
для установки обработчика сигнала
SIGCHLD
, приведенного в листинге 5.6.

linux % tcpserv03 &

[1] 20419

linux % tcpcli04 206.62.226.35

hello мы набираем эту строку

hello и она отражается сервером

^D мы набираем символ конца файла

child 20426 terminated выводится сервером

  • Читать дальше
  • 1
  • ...
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: