-->

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

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

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

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

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

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

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

 struct hostent *hptr;

 ...

 signal(SIGALRM, sig_alrm);

 ...

 hptr = gethostbyname( ... );

 ...

}

void

sig_alrm(int signo) {

 struct hostent *hptr;

 ...

 hptr = gethostbyname( ... );

 ...

}

Если главный поток управления в момент остановки находится в середине выполнения функции

gethostbyname
(допустим, функция заполнила переменную
host
и должна сейчас возвратить управление), а затем обработчик сигналов вызывает функцию
gethostbyname
, то поскольку в процессе существует только один экземпляр переменной
host
, эта переменная используется снова. При этом значения переменных, вычисленные при вызове из главного потока управления, заменяются значениями, вычисленными при вызове из обработчика сигнала.

Если мы посмотрим на функции преобразования имен и адресов, представленные в этой главе и в главе 9, вместе с функциями

inet_<i>XXX</i>
из главы 4, мы заметим следующее:

■ Функции

gethostbyname
,
gethostbyname2
,
gethostbyaddr
,
getservbyname
и
getservbyport
традиционно не допускают повторного вхождения, поскольку все они возвращают указатель на статическую структуру.

Некоторые реализации, поддерживающие программные потоки (Solaris 2.x), предоставляют версии этих четырех функций, допускающие повторное вхождение, с именами, оканчивающимися суффиксом

_r
. О них рассказывается в следующем разделе.

В качестве альтернативы некоторые реализации с поддержкой программных потоков (Digital Unix 4.0 и HP_UX 10.30) предоставляют версии этих функций, допускающие повторное вхождение за счет использования собственных данных программных потоков.

■ Функции

inet_pton
и
inet_ntop
всегда допускают повторное вхождение.

■ Исторически функция

inet_ntoa
не допускает повторное вхождение, но некоторые реализации с поддержкой потоков предоставляют версию, допускающую повторное вхождение, которая строится на основе собственных данных потоков.

■ Функция

getaddrinfo
допускает повторное вхождение, только если она сама вызывает функции, допускающие повторное вхождение, то есть если она вызывает соответствующую версию функции
gethostbyname
или
getservbyname
для имени узла или имени службы. Одной из причин, по которым вся память для результатов ее выполнения выделяется динамически, является возможность повторного вхождения.

■ Функция

getnameinfo
допускает повторное вхождение, только если она сама вызывает такие функции, то есть если она вызывает соответствующую версию функции
gethostbyaddr
для получения имени узла или функции
getservbyport
для получения имени службы. Обратите внимание, что обе результирующих строки (для имени узла и для имени службы) размещаются в памяти вызывающим процессом, чтобы обеспечить возможность повторного вхождения.

Похожая проблема возникает с переменной

errno
. Исторически существовало по одной копии этой целочисленной переменной для каждого процесса. Если процесс выполняет системный вызов, возвращающий ошибку, то в этой переменной хранится целочисленный код ошибки. Например, функция
close
из стандартной библиотеки языка С может выполнить примерно такую последовательность действий:

■ поместить аргумент системного вызова (целочисленный дескриптор) в регистр;

■ поместить значение в другой регистр, указывая, что был сделан системный вызов функции

close
;

■ активизировать системный вызов (переключиться на ядро со специальной инструкцией);

■ проверить значение регистра, чтобы увидеть, что произошла ошибка;

■ если ошибки нет, возвратить (0);

■ сохранить значение какого-то другого регистра в переменной

errno
;

■ возвратить (-1).

Прежде всего заметим, что если ошибки не происходит, значение переменной

errno
не изменяется. Поэтому мы не можем посмотреть значение этой переменной, пока мы не узнаем, что произошла ошибка (обычно на это указывает возвращаемое функцией значение -1).

Будем считать, что программа проверяет возвращаемое значение функции

close
и затем выводит значение переменной
errno
, если произошла ошибка, как в следующем примере:

if (close(fd) &lt; 0) {

 fprintf(stderr, &quot;close error, errno = $dn&quot;, errno);

 exit(1);

}

Существует небольшой промежуток времени между сохранением кода ошибки в переменной errno в тот момент, когда системный вызов возвращает управление, и выводом этого значения программой. В течение этого промежутка другой программный поток внутри процесса (то есть обработчик сигналов) может изменить значение переменной

errno
. Если, например, при вызове обработчика сигналов главный поток управления находится между
close
и
fprintf
и обработчик сигналов делает какой-то другой системный вызов, возвращающий ошибку (допустим, вызывается функция
write
), то значение переменной
errno
, записанное при вызове функции
close
, заменяется на значение, записанное при вызове функции
write
.

При рассмотрении этих двух проблем в связи с обработчиками сигналов одним из решений проблемы с функцией

gethostbyname
(возвращающей указатель на статическую переменную) будет не вызывать из обработчика сигнала функции, которые не допускают повторное вхождение. Проблемы с переменной
errno
(одна глобальная переменная, которая может быть изменена обработчиком сигнала) можно избежать, перекодировав обработчик сигнала так, чтобы он сохранял и восстанавливал значение переменной
errno
следующим образом:

void sig_alrm(int signo) {

int errno_save;

errno_save = errno; /* сохраняем значение этой переменной

                       при вхождении */

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