accept

ACCEPT(2)                Руководство программиста Linux                ACCEPT(2)



ИМЯ
       accept, accept4 - принять соединение на сокете

ОБЗОР
       #include <sys/types.h>          /* См. ЗАМЕЧАНИЯ */
       #include <sys/socket.h>

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

       #define _GNU_SOURCE             /* Смотрите feature_test_macros(7) */
       #include <sys/socket.h>

       int accept4(int sockfd, struct sockaddr *addr,
                   socklen_t *addrlen, int flags);

ОПИСАНИЕ
       Системный вызов accept() используется с сокетами, ориентированными на
       установление соединения (SOCK_STREAM, SOCK_SEQPACKET). Она извлекает
       первый запрос на соединение из очереди ожидающих соединений
       прослушивающего сокета, sockfd, создаёт новый подключенный сокет и и
       возвращает новый файловый дескриптор, указывающий на сокет. Новый сокет
       более не находится в слушающем состоянии. Исходный сокет sockfd не
       изменяется при этом вызове.

       Аргумент sockfd — это сокет, который был создан с помощью socket(2),
       привязанный к локальному адресу с помощью bind(2), и прослушивающий
       соединения после listen(2).

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

       Через аргумент addrlen осуществляется возврат результата: вызывающая
       сторона должна указать в нём размер (в байтах) структуры, на которую
       указывает addr; при возврате он будет содержать реальный размер адреса
       ответной стороны.

       Возвращаемый адрес обрезается, если предоставленный буфер окажется
       слишком маленьким; в этом случае в addrlen будет возвращено значение
       большее чем было в вызове.

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

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

       Если flags равно 0, то вызов accept4() равнозначен accept(). Следующие
       значения могут быть побитово сложены в flags для получения различного
       поведения:

       SOCK_NONBLOCK   Устанавливает флаг состояния файла O_NONBLOCK для нового
                       открытого файлового дескриптора. Использование данного
                       флага заменяет дополнительные вызовы fcntl(2) для
                       достижения того же результата.

       SOCK_CLOEXEC    Устанавливает флаг close-on-exec (FD_CLOEXEC) для нового
                       открытого файлового дескриптора. Смотрите описание флага
                       O_CLOEXEC в open(2) для того, чтобы узнать как это может
                       пригодиться.

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
       При успешном выполнении данные системные вызовы возвращают
       неотрицательное целое, являющееся файловым дескриптором принятого сокета.
       В случае ошибки возвращается -1, а errno устанавливается в
       соответствующее значение.

   Обработка ошибок
       В реализации Linux accept() (и accept4()) передаёт уже ожидающие сетевые
       ошибки на новый сокет, как код ошибки из вызова accept(). Это поведение
       отличается от других реализаций BSD-сокетов. Для надёжной работы
       приложения должны отслеживать сетевые ошибки, которые могут появиться при
       работе с протоколом accept() и обрабатывать их как EAGAIN повторно
       выполняя вызов. В случае TCP/IP такими ошибками являются ENETDOWN,
       EPROTO, ENOPROTOOPT, EHOSTDOWN, ENONET, EHOSTUNREACH, EOPNOTSUPP и
       ENETUNREACH.

ОШИБКИ
       EAGAIN или EWOULDBLOCK
              Сокет помечен как неблокирующий и нет ни одного соединения,
              которое можно было бы принять. В POSIX.1-2001 и POSIX.1-2008
              допускается в этих случаях возврат ошибки и не требуется, чтобы
              эти константы имели одинаковое значение, поэтому переносимое
              приложение должно проверять обе возможности.

       EBADF  Значение sockfd не является открытым файловым дескриптором.

       ECONNABORTED
              Соединение было прервано.

       EFAULT Аргумент addr не находится в пользовательском пространстве адресов
              с возможностью записи.

       EINTR  Системный вызов прервал сигналом, который поступил до момента
              прихода допустимого соединения; см. signal(7).

       EINVAL Сокет не слушает соединения или недопустимое значение addrlen
              (например, отрицательное).

       EINVAL (accept4()) недопустимое значение в flags.

       EMFILE Было достигнуто ограничение по количеству открытых файловых
              дескрипторов на процесс.

       ENFILE Достигнуто максимальное количество открытых файлов в системе.

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

       ENOTSOCK
              Файловый дескриптор sockfd указывает не на каталог.

       EOPNOTSUPP
              Тип сокета, на который ссылается дескриптор, отличается от
              SOCK_STREAM.

       EPROTO Ошибка протокола.

       Также, Linux accept() может завершиться с ошибкой если:

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

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

ВЕРСИИ
       Системный вызов accept4() доступен в Linux начиная с версии 2.6.28;
       поддержка в glibc доступна начиная с версии 2.10.

СООТВЕТСТВИЕ СТАНДАРТАМ
       accept(): POSIX.1-2001, POSIX.1-2008, SVr4, 4.4BSD, (accept() впервые
       появился в 4.2BSD).

       accept4() является нестандартным расширением Linux.

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

ЗАМЕЧАНИЯ
       В POSIX.1-2001 не требуется включение <sys/types.h>, и этот заголовочный
       файл не требуется в Linux. Однако, некоторые старые (BSD) реализации
       требуют данный файл, и в переносимых приложениях для предосторожности,
       вероятно, он будет включён.

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

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

   Тип socklen_t
       Третий аргумент accept() первоначально объявлялся как int * (и так было в
       libc4, libc5 и многих других системах типа 4.x BSD, SunOS 4, SGI); в
       стандарте черновика POSIX.1g захотели изменить его на size_t *, и так
       сделано в SunOS 5. Поздние черновики POSIX содержат socklen_t *, и так
       сделано в Single UNIX Specification и glibc2. Цитируя Линуса Торвальдса
       (Linus Torvalds):

       "_Любая_ нормальная библиотека _должна_ иметь "socklen_t" размером с int.
       Любой другой вариант ломает реализацию BSD-сокетов. В POSIX _сначала_ls
       использовали size_t, но я (и, к счастью, кто-то ещё, хотя и не слишком
       многие) очень громко пожаловались. Такая реализация вообще не работает,
       так как size_t очень редко имеет тот же размер, что и "int", например, на
       64-битных архитектурах. Это необходимо _только_ потому, что так сделано в
       интерфейсе BSD-сокетов. В любом случае, люди из POSIX наконец поняли и
       создали "socklen_t". Вообще, с самого начала они просто не должны были
       ничего трогать, но по какой-то причине они чувствовали, что должны
       использовать именованный тип (вероятно, они не хотели ударить в грязь
       лицом сделав глупость, поэтому они тихо переименовали место, в котором
       просчитались)."

ПРИМЕР
       См. bind(2).

СМОТРИТЕ ТАКЖЕ
       bind(2), connect(2), listen(2), select(2), socket(2), socket(7)



Linux                              2016-03-15                          ACCEPT(2)