Чтение онлайн

на главную

Жанры

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

Если трехэтапное рукопожатие завершается нормально (то есть без потерянных сегментов и повторных передач), запись остается в очереди не полностью установленных соединений на время одного периода обращения (round-trip time, RTT), какое бы значение ни имел этот параметр для конкретного соединения между клиентом и сервером. В разделе 14.4 [112] показано, что для одного веб-сервера средний период RTT оказался равен 187 мс. (Чтобы редкие большие числа не искажали картину, здесь использована медиана, а не обычное среднее арифметическое по всем клиентам.)

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

backlog
, равное 5, поскольку это было максимальное значение, которое поддерживалось в системе 4.2BSD. Это было актуально в 80-х, когда загруженные серверы могли обрабатывать только несколько сотен соединений в день. Но с ростом Сети (WWW), когда серверы обрабатывают миллионы соединений в день, столь малое число стало абсолютно неприемлемым [112, с. 187–192]. Серверам HTTP необходимо намного большее значение аргумента
backlog
, и новые ядра должны поддерживать такие значения.

ПРИМЕЧАНИЕ

В

настоящее время многие системы позволяют администраторам изменять максимальное значение аргумента backlog.

Возникает вопрос: какое значение аргумента

backlog
должно задавать приложение, если значение 5 часто является неадекватным? На этот вопрос нет простого ответа. Серверы HTTP сейчас задают большее значение, но если заданное значение является в исходном коде константой, то для увеличения константы требуется перекомпиляция сервера. Другой способ — принять некоторое значение по умолчанию и предоставить возможность изменять его с помощью параметра командной строки или переменной окружения. Всегда можно задавать значение больше того, которое поддерживается ядром, так как ядро должно обрезать значение до максимального, не возвращая при этом ошибку [128, с. 456].

Мы приводим простое решение этой проблемы, изменив нашу функцию-обертку для функции

listen
. В листинге 4.1 [1] представлен действующий код. Переменная окружения
LISTENQ
позволяет переопределить значение по умолчанию.

Листинг 4.1. Функция-обертка для функции listen, позволяющая переменной окружения переопределить аргумент backlog

//lib/wrapsock.c

137 void

138 Listen(int fd, int backlog)

1

Все исходные коды программ, опубликованные в этой книге, вы можете найти по адресу http://www.piter.com.

139 {

140 char *ptr;

141 /* может заменить второй аргумент на переменную окружения */

142 if ((ptr = getenv("LISTENQ")) != NULL)

143 backlog = atoi(ptr);

144 if (listen(fd, backlog) < 0)

145 err_sys("listen error");

146 }

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

accept
. При этом подразумевается, что из двух очередей больше записей будет содержаться, вероятнее всего, в очереди полностью установленных соединений. Но оказалось, что для действительно загруженных веб-серверов это не так. Причина задания большего значения
backlog
в том, что очередь не полностью установленных соединений растет по мере поступления сегментов SYN от клиентов; элементы очереди находятся в состоянии ожидания завершения трехэтапного рукопожатия.

Если очереди заполнены, когда приходит клиентский сегмент SYN, то TCP игнорирует приходящий сегмент SYN [128, с. 930–931] и не посылает RST. Это происходит потому, что состояние считается временным, и TCP клиента должен еще раз передать свой сегмент SYN, для которого в ближайшее время, вероятно, найдется место в очереди. Если бы TCP сервера послал RST, функция

connect
клиента сразу же возвратила бы ошибку, заставив приложение обработать это условие, вместо того чтобы позволить TCP выполнить повторную передачу. Кроме того, клиент не может увидеть разницу между сегментами RST в ответе на сегмент SYN, означающими, что на данном порте нет сервера либо на данном порте есть сервер, но его очереди заполнены.

ПРИМЕЧАНИЕ

Некоторые реализации отправляют сегмент RST в описанной выше ситуации, что некорректно по изложенным выше причинам. Если вы не пишете клиент специально для работы с подобным сервером, лучше всего игнорировать такую возможность. Ее учет при кодировании клиента снизит его устойчивость и увеличит нагрузку на сеть, если окажется, что порт действительно не прослушивается сервером.

Данные, которые приходят после завершения трехэтапного рукопожатия, но до того, как сервер вызывает функцию

accept
, должны помещаться в очередь TCP-сервера, пока не будет заполнен приемный буфер.

В табл. 4.6 показано действительное число установленных в очередь соединений для различных значений аргумента

backlog
в операционных системах, показанных на рис. 1.7. Семь операционных систем помещены в пять колонок, что иллюстрирует многообразие значений аргумента
backlog
.

Таблица 4.6. Действительное количество соединений в очереди для различных значений аргумента backlog

backlog MacOS 10.2.6 AIX 5.1 Linux 2.4.7 HP-UX 11.11 FreeBSD 4.8 FreeBSD 5.1 Solaris 2.9
0 1 3 1 1 1
1 2 4 1 2 2
2 4 5 3 3 4
3 5 6 4 4 5
4 7 7 6 5 6
5 8 8 7 6 8
6 10 9 9 7 10
7 И 10 10 8 11
8 13 11 12 9 13
9 14 12 13 10 14
10 16 13 15 11 16
11 17 14 16 12 17
12 19 15 18 13 19
13 20 16 19 14 20
14 22 17 21 15 22

Системы AIX, BSD/ОХ

и SunOS реализуют традиционный алгоритм Беркли, хотя последний не допускает значения аргумента backlogбольше пяти. В системах HP-UX и Solaris 2.6 используется другой поправочный множитель к аргументу
backlog
. Системы Digital Unix, Linux и UnixWare воспринимают этот аргумент буквально, то есть не используют поправочный множитель, а в Solaris 2.5.1 к аргументу
backlog
просто добавляется единица.

ПРИМЕЧАНИЕ

Программа для измерения этих значений представлена в решении упражнения 15.4.

Как мы отмечали, традиционно аргумент backlog задавал максимальное значение для суммы обеих очередей. В 1996 году была предпринята новая атака через Интернет, названная SYN flooding (лавинная адресация сегмента SYN). Написанная хакером программа отправляет жертве сегменты SYN с высокой частотой, заполняя очередь не полностью установленных соединений для одного или нескольких портов TCP. (Хакером мы называем атакующего, как сказано в предисловии к [20].) Кроме того, IP-адрес отправителя каждого сегмента SYN задается случайным числом — формируются вымышленные IP-адреса (IP spoofing), что ведет к получению доступа обманным путем. Таким образом, сегмент сервера SYN/ACK уходит в никуда. Это не позволяет серверу узнать реальный IP-адрес хакера. Очередь не полностью установленных соединений заполняется ложными сегментами SYN, в результате чего для подлинных сегментов SYN в ней не хватает места — происходит отказ в обслуживании (denial of service) нормальных клиентов. Существует два типичных способа противостояния этим атакам [8]. Но самое интересное в этом примечании — это еще одно обращение к вопросу о том, что на самом деле означает аргумент backlog функции listen. Он должен задавать максимальное число установленных соединений для данного сокета, которые ядро помещает в очередь. Ограничение количества установленных соединений имеет целью приостановить получение ядром новых запросов на соединение для данного сокета, когда их не принимает приложение (по любой причине). Если система реализует именно такую интерпретацию, как, например, BSD/OS 3.0, то приложению не нужно задавать большие значения аргумента backlog только потому, что сервер обрабатывает множество клиентских запросов (например, занятый веб-сервер), или для защиты от «наводнения» SYN (лавинной адресации сегмента SYN). Ядро обрабатывает множество не полностью установленных соединений вне зависимости от того, являются ли они законными или приходят от хакера. Но даже в такой интерпретации мы видим (см. табл. 4.6), что значения 5 тут явно недостаточно.

4.6. Функция accept

Функция

accept
вызывается сервером TCP для возвращения следующего установленного соединения из начала очереди полностью установленных соединений (см. рис. 4.2). Если очередь полностью установленных соединений пуста, процесс переходит в состояние ожидания (по умолчанию предполагается блокируемый сокет).

#include <sys/socket.h>

int accept(int sockfd, struct sockaddr * cliaddr, socklen_t * addrlen);

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

Последний Паладин. Том 3

Саваровский Роман
3. Путь Паладина
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Последний Паладин. Том 3

Последний попаданец 5

Зубов Константин
5. Последний попаданец
Фантастика:
юмористическая фантастика
рпг
5.00
рейтинг книги
Последний попаданец 5

Убивать чтобы жить 6

Бор Жорж
6. УЧЖ
Фантастика:
боевая фантастика
космическая фантастика
рпг
5.00
рейтинг книги
Убивать чтобы жить 6

6 Секретов мисс Недотроги

Суббота Светлана
2. Мисс Недотрога
Любовные романы:
любовно-фантастические романы
эро литература
7.34
рейтинг книги
6 Секретов мисс Недотроги

Измена

Рей Полина
Любовные романы:
современные любовные романы
5.38
рейтинг книги
Измена

Курсант: Назад в СССР 13

Дамиров Рафаэль
13. Курсант
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Курсант: Назад в СССР 13

Газлайтер. Том 6

Володин Григорий
6. История Телепата
Фантастика:
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Газлайтер. Том 6

Купидон с топором

Юнина Наталья
Любовные романы:
современные любовные романы
7.67
рейтинг книги
Купидон с топором

Виконт. Книга 3. Знамена Легиона

Юллем Евгений
3. Псевдоним `Испанец`
Фантастика:
фэнтези
попаданцы
аниме
7.00
рейтинг книги
Виконт. Книга 3. Знамена Легиона

Попаданка в деле, или Ваш любимый доктор - 2

Марей Соня
2. Попаданка в деле, или Ваш любимый доктор
Любовные романы:
любовно-фантастические романы
7.43
рейтинг книги
Попаданка в деле, или Ваш любимый доктор - 2

Усадьба леди Анны

Ром Полина
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Усадьба леди Анны

Титан империи 2

Артемов Александр Александрович
2. Титан Империи
Фантастика:
фэнтези
боевая фантастика
аниме
5.00
рейтинг книги
Титан империи 2

Вечный. Книга I

Рокотов Алексей
1. Вечный
Фантастика:
боевая фантастика
попаданцы
рпг
5.00
рейтинг книги
Вечный. Книга I

Убивать чтобы жить 5

Бор Жорж
5. УЧЖ
Фантастика:
боевая фантастика
космическая фантастика
рпг
5.00
рейтинг книги
Убивать чтобы жить 5