1. Когда сокет создается с помощью функции
socket
, считается, что это активный сокет, то есть клиентский сокет, который запустит функцию
connect
. Функция
listen
преобразует неприсоединенный сокет в пассивный сокет, запросы на подключение к которому начинают приниматься ядром. В терминах диаграммы перехода между состояниями TCP (см. рис. 2.4) вызов функции
listen
переводит сокет из состояния CLOSED в состояние LISTEN.
2. Второй аргумент этой функции задает максимальное число соединений, которые ядро может помещать в очередь этого сокета.
#include
int listen(int
Эта функция обычно вызывается после функций
socket
и
bind
. Она должна вызываться перед вызовом функции
accept
.
Чтобы уяснить смысл аргумента
backlog
, необходимо понять, что для данного прослушиваемого сокета ядро поддерживает две очереди:
1.
2.
На рис. 4.2 представлены обе эти очереди для прослушиваемого сокета.
Рис. 4.2. Две очереди, поддерживаемые прослушиваемым сокетом TCP
Когда в очередь не полностью установленных соединений добавляется новая запись, параметры прослушиваемого сокета копируются на создаваемое соединение. Механизм создания соединения полностью автоматизирован, и процесс сервера в нем не участвует. На рис. 4.3 показан обмен пакетами во время установления соединения с использованием этих очередей.
Рис. 4.3. Обмен пакетами в процессе установления соединения с применением очередей
Когда от клиента приходит сегмент SYN, TCP создает новую запись в очереди не полностью установленных соединений, а затем отвечает вторым сегментом трехэтапного рукопожатия, посылая сегмент SYN вместе с сегментом ACK, подтверждающим прием клиентского сегмента SYN (см. раздел 2.6). Эта запись останется в очереди не полностью установленных соединений, пока не придет третий сегмент трехэтапного рукопожатия (клиентский сегмент ACK для сегмента сервера SYN) или пока не истечет время жизни этой записи. (В реализациях, происходящих от Беркли, время ожидания (тайм-аут) для элементов очереди не полностью установленных соединений равно 75 с.) Если трехэтапное рукопожатие завершается нормально, запись переходит из очереди не полностью установленных соединений в конец очереди полностью установленных соединений. Когда процесс вызывает функцию
accept
(о которой мы поговорим в следующем разделе), ему возвращается первая запись из очереди полностью установленных соединений, а если очередь пуста, процесс переходит в состояние ожидания до появления записи в ней.
Есть несколько важных моментов, которые нужно учитывать при работе с этими очередями.
Аргумент
listen
исторически задавал максимальное суммарное значение для обеих очередей.
Беркли-реализации включают поправочный множитель для аргумента
backlog
, равный 1,5 [111, с. 257], [128, с. 462]. Например, при типичном значении аргумента
backlog
= 5 в таких системах допускается до восьми записей в очередях, как показано в табл. 4.6.
Формального определения аргумента backlog никогда не существовало. В руководстве 4.2BSD сказано, что «он определяет максимальную длину, до которой может вырасти очередь не полностью установленных соединений». Многие руководства и даже POSIX копируют это определение дословно, но в нем не говорится, в каком состоянии должно находится соединение — в состоянии SYN_RCVD, ESTABLISHED (до вызова accept), или же в любом из них. Определение, приведенное выше, относится к реализации Беркли 4.2BSD, и копируется многими другими реализациями.