Уильям Стивенс - UNIX: разработка сетевых приложений
- Название:UNIX: разработка сетевых приложений
- Автор:
- Жанр:
- Издательство:Питер
- Год:2007
- Город:Санкт-Петербург
- ISBN:5-94723-991-4
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Уильям Стивенс - UNIX: разработка сетевых приложений краткое содержание
Новое издание книги, посвященной созданию веб-серверов, клиент-серверных приложений или любого другого сетевого программного обеспечения в операционной системе UNIX, — классическое руководство по сетевым программным интерфейсам, в частности сокетам. Оно основано на трудах Уильяма Стивенса и полностью переработано и обновлено двумя ведущими экспертами по сетевому программированию. В книгу включено описание ключевых современных стандартов, реализаций и методов, она содержит большое количество иллюстрирующих примеров и может использоваться как учебник по программированию в сетях, так и в качестве справочника для опытных программистов.
UNIX: разработка сетевых приложений - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
Функция signal
Согласно POSIX, чтобы определить действие для сигнала, нужно вызвать функцию sigaction
. Однако это достаточно сложно, поскольку один аргумент этой функции — это структура, для которой необходимо выделение памяти и заполнение. Поэтому проще задать действие сигнала с помощью функции signal
. Первый ее аргумент — это имя сигнала, а второй — либо указатель на функцию, либо одна из констант SIG_IGN
и SIG_DFL
. Но функция signal
существовала еще до появления POSIX.1, и ее различные реализации имеют разную семантику сигналов с целью обеспечения обратной совместимости. В то же время POSIX четко диктует семантику при вызове функции sigaction
. Это обеспечивает простой интерфейс с соблюдением семантики POSIX. Мы включили эту функцию в нашу собственную библиотеку вместе функциями err_ XXX
и функциями-обертками, которые мы используем для построения всех наших программ. Она представлена в листинге 5.5. Функция-обертка Signal
здесь не показана, потому что ее вид не зависит от того, какую именно функцию signal
она должна вызывать.
Листинг 5.5. Функция signal, вызывающая функцию POSIX sigaction
//lib/signal.c
1 #include "unp.h"
2 Sigfunc*
3 signal(int signo, Sigfunc *func)
4 {
5 struct sigaction act, oact;
6 act.sa_handler = func;
7 sigemptyset(&act.sa_mask);
8 act.sa_flags = 0;
9 if (signo == SIGALRM) {
10 #ifdef SA_INTERRUPT
11 act.sa_flags |= SA_INTERRUPT; /* SunOS 4.x */
12 #endif
13 } else {
14 #ifdef SA_RESTART
15 act.sa_flags |= SA_RESTART; /* SVR4, 44BSD */
16 #endif
17 }
18 if (sigaction(signo, &act, &oact) < 0)
19 return (SIG_ERR);
20 return (oact.sa_handler);
21 }
2-3
Обычный прототип для функции signal
усложняется наличием вложенных скобок:
void (*signal(int signo , void (* func )(int)))(int);
Чтобы упростить эту запись, мы определяем тип Sigfunc
в нашем заголовочном файле unp.h
следующим образом:
typedef void Sigfunc(int);
указывая тем самым, что обработчики сигналов — это функции с целочисленным аргументом, ничего не возвращающие ( void
). Тогда прототип функции выглядит следующим образом:
Sigfunc *signal(int signo , Sigfunc * func );
Указатель на функцию, являющуюся обработчиком сигнала, — это второй аргумент функции и в то же время возвращаемое функцией значение.
6
Элемент sa_handler
структуры sigaction
устанавливается равным аргументу func
функции signal
.
7
POSIX позволяет нам задавать набор сигналов, которые будут блокированы при вызове обработчика сигналов. Любой блокируемый сигнал не может быть доставлен процессу. Мы устанавливаем элемент sa_mask
равным пустому набору. Это означает, что во время работы обработчика дополнительные сигналы не блокируются. POSIX гарантирует, что перехватываемый сигнал всегда блокирован, пока выполняется его обработчик.
8-17
Флаг SA_RESTART
не является обязательным, и если он установлен, то системный вызов, прерываемый этим сигналом, будет автоматически снова выполнен ядром. (В продолжении нашего примера мы более подробно поговорим о прерванных системных вызовах.) Если перехватываемый сигнал не является сигналом SIGALRM
, мы задаем флаг SA_RESTART
, если таковой определен. (Причина, по которой сигнал SIGALRM
обрабатывается отдельно, состоит в том, что обычно цель его генерации - ввести ограничение по времени в операцию ввода-вывода, как показано в листинге 14.2. В этом случае мы хотим, чтобы блокированный системный вызов был прерван сигналом.) Более ранние системы, особенно SunOS 4.x, автоматически перезапускают прерванный системный вызов по умолчанию и затем определяют флаг SA_INTERRUPT
. Если этот флаг задан, мы устанавливаем его при перехвате сигнала SIGALRM
.
18-20
Мы вызываем функцию sigaction
, а затем возвращаем старое действие сигнала как результат функции signal
.
В книге мы везде используем функцию signal
из листинга 5.5.
Семантика сигналов POSIX
Сведем воедино следующие моменты, относящиеся к обработке сигналов в системе, совместимой с POSIX.
■ Однажды установленный обработчик сигналов остается установленным (в более ранних системах обработчик сигналов удалялся каждый раз по выполнении).
■ На время выполнения функции — обработчика сигнала доставляемый сигнал блокируется. Более того, любые дополнительные сигналы, заданные в наборе сигналов sa_mask
, переданном функции sigaction
при установке обработчика, также блокируются. В листинге 5.5 мы устанавливаем sa_mask
равным пустому набору, что означает, что никакие сигналы, кроме перехватываемого, не блокируются.
■ Если сигнал генерируется один или несколько раз, пока он блокирован, то обычно после разблокирования он доставляется только один раз, то есть по умолчанию сигналы Unix не устанавливаются в очередь . Пример мы рассмотрим в следующем разделе. Стандарт POSIX реального времени 1003.1b определяет набор надежных сигналов, которые помещаются в очередь, но в этой книге мы их не используем.
■ Существует возможность выборочного блокирования и разблокирования набора сигналов с помощью функции sigprocmask
. Это позволяет нам защитить критическую область кода, не допуская перехватывания определенных сигналов во время ее выполнения.
5.9. Обработка сигнала SIGCHLD
Назначение состояния зомби — сохранить информацию о дочернем процессе, чтобы родительский процесс мог ее впоследствии получить. Эта информация включает идентификатор дочернего процесса, статус завершения и данные об использовании ресурсов (время процессора, память и т.д.). Если у завершающегося процесса есть дочерний процесс в зомбированном состоянии, идентификатору родительского процесса всех зомбированных дочерних процессов присваивается значение 1 (процесс init
), что позволяет унаследовать дочерние процессы и сбросить их (то есть процесс init
будет ждать ( wait
) их завершения, благодаря чему будут удалены зомби). Некоторые системы Unix в столбце COMMAND
выводят для зомбированных процессов значение .
Обработка зомбированных процессов
Очевидно, что нам не хотелось бы оставлять процессы в виде зомби. Они занимают место в ядре, и в конце концов у нас может не остаться идентификаторов для нормальных процессов. Когда мы выполняем функцию fork
для дочерних процессов, необходимо с помощью функции wait
дождаться их завершения, чтобы они не превратились в зомби. Для этого мы устанавливаем обработчик сигналов для перехватывания сигнала SIGCHLD
и внутри обработчика вызываем функцию wait
. (Функции wait
и waitpid
мы опишем в разделе 5.10.) Обработчик сигналов мы устанавливаем с помощью вызова функции
Интервал:
Закладка: