UNIX: разработка сетевых приложений
UNIX: разработка сетевых приложений читать книгу онлайн
Новое издание книги, посвященной созданию веб-серверов, клиент-серверных приложений или любого другого сетевого программного обеспечения в операционной системе UNIX, — классическое руководство по сетевым программным интерфейсам, в частности сокетам. Оно основано на трудах Уильяма Стивенса и полностью переработано и обновлено двумя ведущими экспертами по сетевому программированию. В книгу включено описание ключевых современных стандартов, реализаций и методов, она содержит большое количество иллюстрирующих примеров и может использоваться как учебник по программированию в сетях, так и в качестве справочника для опытных программистов.
Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних чтение данного контента СТРОГО ЗАПРЕЩЕНО! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту [email protected] для удаления материала
Мы не уменьшаем значение переменной
maxi
Этот сервер сложнее, чем сервер, показанный в листингах 5.1 и 5.2, но он позволяет избежать затрат на создание нового процесса для каждого клиента, что является хорошим примером использования функции
select
accept
Атака типа «отказ в обслуживании»
К сожалению, функционирование только что описанного сервера вызывает проблемы. Посмотрим, что произойдет, если некий клиент-злоумышленник соединится с сервером, отправит 1 байт данных (отличный от разделителя строк) и войдет в состояние ожидания. Сервер вызовет функцию
readline
read
Дело в том, что обрабатывая множество клиентов, сервер никогда не должен блокироваться в вызове функции, относящейся к одному клиенту. В противном можно «подвесить» сервер, что приведет к отказу в обслуживании для всех остальных клиентов. Это называется атакой типа «отказ в обслуживании» (DoS attack — Denial of Service). Такая атака воздействует на сервер, делая невозможным обслуживание нормальных клиентов. Обезопасить себя от подобных атак позволяют следующие решения: использовать неблокируемый ввод-вывод (см. главу 16), предоставлять каждому клиенту обслуживание отдельным потоком (например, для каждого клиента порождать процесс или поток) или установить тайм-аут для ввода-вывода (см. раздел 14.2).
6.9. Функция pselect
Функция
pselect
#include <sys/select.h>
#include <signal.h>
#include <time.h>
int pselect(int <i>maxfdp1</i>, fd_set *<i>readset</i>, fd_set *<i>writeset</i>, fd_set *<i>exceptset</i>,
const struct timespec *<i>timeout</i>, const sigset_t *<i>sigmask</i>);
<i>Возвращает: количество готовых дескрипторов, 0 в случае тайм-аута, -1 в случае ошибки</i>
Функция
pselect
select
1. Функция
pselect
timespec
timeval
struct timespec {
time_t tv_sec; /* секунды */
long tv_nsec; /* наносекунды */
};
Эти структуры отличаются вторыми элементами: элемент
tv_nsec
tv_usec
2. В функции
pselect
pselect
В отношении второго пункта рассмотрим следующий пример (описанный на с. 308–309 [110]). Обработчик сигнала нашей программы для сигнала
SIGINT
intr_flag
errno
EINTR
select
if (intr_flag)
handle_intr(); /* обработка этого сигнала */
if ((nready = select(...)) < 0) {
if (errno == EINTR) {
if (intr_flag)
handle_intr();
}
...
}
Проблема заключается в том, что если сигнал придет в промежутке между проверкой переменной
intr_flag
select
select
pselect
sigset_t newmask, oldmask, zeromask;
sigemptyset(&zeromask);
sigemptyset(&newmask);
sigaddset(&newmask, SIGINT);
sigprocmask(SIG_BLOCK, &newmask, &oldmask); /* блокирование сигнала SIGINT */
if (intr_flag)
handle_intr(); /* обработка этого сигнала */
if ((nready = pselect(..., &zeromask)) < 0) {
if (errno == EINTR) {
if (intr_flag)
handle_intr();
}
...
}
Перед проверкой переменной
intr_flag
SIGINT
pselect
zeromask
pselect
pselect
SIGINT