Книга: Разработка приложений в среде Linux. Второе издание
17.3.4. Ожидание соединений
17.3.4. Ожидание соединений
После создания сокета сервер привязывает к нему адрес с помощью функции bind()
. Далее процесс сообщает системе путем вызова функции listen()
, что он готов разрешить другим процессам соединение с данным сокетом (по указанному адресу). Если сокет привязан к адресу, ядро получает возможность обрабатывать попытки соединения с данным адресом, поступающие от процессов. Однако соединение не устанавливается немедленно. Слушающий процесс сначала должен согласиться с попыткой соединения через системный вызов accept()
. До тех пор, пока новая попытка соединения с определенным адресом не принята, она называется ожидающим соединением.
Как правило, функция accept()
блокируется до тех пор, пока к ней не пытается присоединиться некоторый клиентский процесс. Если сокет был помечен как неблокируемый через fcntl()
, то функция accept()
возвращает значение EAGAIN
в том случае, если нет ни одного доступного клиентского процесса[120]. Системные вызовы select()
, poll()
и epoll
могут использоваться для указания, ждать ли соединению обработки (эти вызовы помечают сокет как готовый для считывания)[121].
Ниже показаны прототипы listen()
и accept()
.
#include <sys/socket.h>
int listen(int sock, int backlog);
int accept(int sock, struct sockaddr * addr, socklen_t * addrlen);
В обеих функциях предполагается, что первый параметр — это файловый дескриптор. Второй параметр backlog
функции listen()
задает максимальное количество соединений, которые могут одновременно ожидать обработки на данном сокете. Сетевые соединения не устанавливаются до тех пор, пока сервер не примет соединение через accept()
; все входящие соединения считаются приостановленными. Поддерживая небольшое количество ожидающих соединений в очереди, ядро тем самым освобождает серверные процессы от необходимости быть в постоянной готовности принимать соединения. Исторически принято ограничивать в приложениях количество невыполненных заданий пятью, хотя иногда необходимо большее количество. Функция listen()
возвращает ноль в случае успеха и какое-то другое число в случае неудачи.
Вызов accept()
превращает отложенное соединение в установленное. Установленное соединение получает новый файловый дескриптор, который возвращает функция accept()
. Новый дескриптор наследует все атрибуты того сокета, к которому обращалась функция listen()
. Необычное свойство accept()
состоит в том, что она возвращает сетевые ошибки, ожидающие обработки, как ошибки принятия от accept()
[122]. При возврате ошибки серверы не должны прерывать работу, если параметр errno
принимает одно из следующих значений: ECONNABORTED
, ENETDOWN
, EPROTO
, ENOPROTOOPT
, EHOSTDOWN
, ENONET
, EHOSTUNREACH
, EOPNOTSUPP
или ENETUNREACH
. Все эти ошибки необходимо игнорировать, просто вызвав функцию accept()
на сервере еще раз.
Параметры addr
и addrlen
указывают данные, в которых ядро размещает адрес удаленного (клиентского) конца соединения. В исходном состоянии addrlen
представляет собой целое число, содержащее размер буфера, на который ссылается addr
. Функция accept()
аналогично open() возвращает файловый дескриптор или некоторое отрицательное значение, если возникла ошибка.
- 17.4.2. Ожидание соединения
- 17.3.2. Установка соединений
- 17.5.7. Ожидание TCP-соединений
- Улучшенный протокол локальных соединений (XNET)
- Ожидание процесса
- Глава пятая. Затянувшееся ожидание
- Листинг 5.4. (sem_pv.c) Ожидание и установка двоичного семафора
- 13.2.7. Ожидание события
- Использование PPP-соединений
- 6.3. Изображение резьбовых соединений с крепежными деталями
- Туннелирование X-соединений через SSH
- 10.5.1. Запуск и ожидание с помощью system()