Документация по LinuxLinuxDoc.Ru 🔍

accept - принять соединение на сокете

НАЗВАНИЕ
accept - принять соединение на сокете

СИНТАКСИС

#include
#include

int accept(int s, struct sockaddr *addr, socklen_t
*addrlen);

ОПИСАНИЕ
Функция accept используется с сокетами типов (SOCK_STREAM,
SOCK_SEQPACKET и SOCK_RDM). Эта функция выбирает первый
запрос на соединение из очереди ожидающих соединений,
создает новый сокет с теми же свойствами, что и у s, и
выделяет для сокета новый файловый описатель, который
возвратится этой функцией. Новый созданный сокет уже не
будет находится в состоянии ожидания соединения. При этом
вызове исходный сокет s не изменяется. Обратите внимание,
что любые флаги описателя файла (например, состояния
non-blocking или async, которые могут быть установлены
функцией fcntl с командой F_SETFL) не наследуются от
accept.

Аргумент s - это сокет, который был создан с помощью
функции socket(2), привязан к локальному адресу с помощью
функции bind(2), и ожидает входящие соединения после
вызова функции listen(2). Аргумент addr - указатель на
структуру sockaddr. В эту структуру записан адрес
подключающейся стороны, известный на уровне соединения.
Точный формат адреса, передавемого в аргументе addr,
определяется семейством сокета (см. socket(2) и страницы
руководства по соответствующему протоколу). Аргумент
addrlen - параметр, в который после вызова функции
помещается результат. Перед вызовом функции он содержит
размер структуры на которую указывает R addr ; после
вызова он будет содержать фактическую длину (в байтах)
адреса. Если в addr записано значение NULL, то он не
заполняется.

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

Для того, чтобы получать уведомления о входящих
подключениях на сокете, вы можете использовать select(2)
или poll(2). В этом случае, когда придет запрос на новое
соединение, будет получено событие "можно читать", и тогда
вы можете вызвать accept, чтобы получить сокет для этого
соединения. В другом случае, вы можете заставить сокет
передавать сигнал SIGIO, когда он активируется; см.
socket(7) для уточнения подробностей.

Для некоторых протоколов, которые требуют явного
подтверждения, напр. DECNet, вызов accept можно
рассматривать просто как извлечение из очереди следующего
запроса на подключение без подтверждения. Подтверждение
произойдет при чтении или записи в новый файловый
описатель, а отказ от соединения может произойти при
закрытии нового сокета. В настоящий момент под Linux
такую особенность имеет только DECNet.

ЗАМЕЧАНИЯ
Не всегда после получения сигнала SIGIO или после возврата
из select(2) или из poll(2) в очереди будет находиться
соединение. Оно может быть удалено асинхронной сетевой
ошибкой или другим потоком до вызова accept. Если такое
случается, то вызов будет блокирует ожидание до следующего
подключения. Чтобы гарантировать, что accept никогда не
заблокируется, в сокете s должен быть установлен флаг
O_NONBLOCK (см. socket(7)).

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ

В случае ошибки функция возвращает значение -1. При
успешном завершении возвращается неотрицательное целое
значение, являющееся описателем сокета.

ОБРАБОТКА ОШИБОК
В Linux accept сообщает об ожидающих в очереди сетевых
ошибках, возвращая их код при вызове accept. Это
поведение отличается от других реализаций сокетов BSD.
Для надежной работы приложения должны отслеживать сетевые
ошибки, определенные для протокола, и обрабатывать их как
EAGAIN, с помощью повторного выполнения функции. В случае
TCP/IP такими ошибками являются ENETDOWN, EPROTO, ENOPRO-
TOOPT, EHOSTDOWN, ENONET, EHOSTUNREACH, EOPNOTSUPP, и ENE-
TUNREACH.

КОДЫ ОШИБОК
EAGAIN или EWOULDBLOCK
Сокет отмечен как non-blocking, но нет ни одного
соединения, которое можно принять.

EBADF Неправильный описатель.

ENOTSOCK
Описатель указывает на файл (не на сокет).

EOPNOTSUPP
Сокет, на который указывает описатель, имеет тип,
отличный от SOCK_STREAM.

EFAULT Параметр addr находится в пространстве адресов с
запрещенной записью.

EPERM Правила сетевого экрана (firewall) запрещают
соединение.

EINTR Системный вызов был прерван сигналом перехваченным
до того, как было установлено корректное
соединение. ENOBUFS, ENOMEM Не хватает свободной
памяти. Часто это означает, что распределение
памяти ограничено пределами буфера сокета, а не
памятью системы, но это не обязательно может быть
так.

В дополнение к этим ошибкам, могут также возвращаться
сетевые ошибки сокета и ошибки, определенные для
протокола. Различные ядра Linux могут вернуть другие
ошибки, например, EMFILE, EINVAL, ENOSR, ENOBUFS, EPERM,
ECONNABORTED, ESOCKTNOSUPPORT, EPROTONOSUPPORT, ETIMEDOUT.
Значение ERESTARTSYS может быть получено во время
трассировки.

СООТВЕТСТВИЕ СТАНДАРТАМ
SVr4, 4.4BSD (функция accept впервые появилась в BSD 4.2).
Руководство BSD описывает пять возможных кодов ошибок
(EBADF, ENOTSOCK, EOPNOTSUPP, EWOULDBLOCK, EFAULT). SUSv2
описывает ошибки EAGAIN, EBADF, ECONNABORTED, EFAULT,
EINTR, EINVAL, EMFILE, ENFILE, ENOBUFS, ENOMEM, ENOSR,
ENOTSOCK, EOPNOTSUPP, EPROTO, EWOULDBLOCK.

Linux _не_ наследует флаги сокета, подобного O_NONBLOCK.
Это поведение отличается от других реализаций BSD сокетов.
Переносимые программы не должны полагаться на это
поведение и всегда устанавливать все требуемые флаги на
сокете, возвращенные функцией accept.

ЗАМЕЧАНИЕ
Третий аргумент функции accept изначально был определен
как int * (именно так это сделано в libc4, libc5 и во
многих системах, включая BSD 4.*, SunOS и SGI); черновик
стандарта POSIX 1003.1g пытался поменять этот тип на
size_t *, и в SunOS 5 это именно так. Более поздние
черновики POSIX содержат socklen_t *, и в Single Unix
Specification и glibc2 это сделано таким образом. По
словам Линуса Торвальдса:
В _любой_ разумной библиотеке размеры "socklen_t" и int
_должны_ совпадать. Любой другой вариант несовместим с
реализацией сокетов BSD. В POSIX сначала использовали
size_t, но я (и, к счастью, кто-то еще, хотя и не слишком
многие) сильно возмутились по этому поводу. Такая
реализация полностью поломана как раз потому, что size_t
очень редко имеет тот же размер, что и "int", например, в
64-битных архитектурах. Это необходимо потому, что
интерфейс сокетов BSD таков, каков он есть. В любом
случае, люди из POSIX наконец поняли и создали
"socklen_t". Вообще, с самого начала они просто не должны
были ничего трогать, но по какой-то причине они
чувствовали, что должны использовать поименованный тип
(вероятно, они не хотели ударить в грязь лицом, сделав
глупость, поэтому они тихо переименовали свою грубую
ошибку).
Читать новости Linux в Telegram
Linux - accept - принять соединение на сокете
Мы в соцсетях ✉