accept

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



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

КРАТКАЯ СВОДКА
       #include <sys/types.h>
       #include <sys/socket.h>

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

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


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

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

       Если в очереди нет запросов на соединение, а сокет не маркирован как
       неблокирующий, то accept блокирует вызвавшую программу до появления
       соединения.  Если сокет маркирован как неблокирующий, а в очереди нет
       запросов на соединение, то 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 в случае ошибки.  При успешном
       завершении возвращается неотрицательное целое, являющееся дескриптором
       сокета.


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

ОШИБКИ
       EAGAIN или EWOULDBLOCK
              Сокет маркирован как неблокирующий, но нет ни одного соединения,
              которое можно было бы принять.

       EBADF  Дескриптор неправилен.

       ENOTSOCK
              Дескриптор ссылается на файл, а не на сокет.

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

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

       EPERM  Правила на файерволле запрещают соединение.

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

       Вдобавок, могут также возвращаться сетевые ошибки на новом сокете и
       ошибки, могущие возникнуть в протоколе.  Различные ядра 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.
       Реализация accept в Linux _не_ наследует флаги сокетов (типа O_NONBLOCK).
       Это поведение отличается от других реализаций BSD-сокетов.  Переносимые
       программы не должны полагаться на такое поведение и всегда должны
       устанавливать на сокете, полученном от accept, все требуемые флаги.


ЗАМЕЧАНИЕ
       Третий аргумент функции accept изначально был объявлен как int * (это
       именно так в libc4, libc5 и на многих других системах, включая BSD 4.*,
       SunOS 4 и 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".
       Вообще, с самого начала они просто не должны были ничего трогать, но по
       какой-то причине они чувствовали, что должны использовать поименованный
       тип (вероятно, они не хотели ударить в грязь лицом, сделав глупость,
       поэтому они тихо переименовали место, в котором просчитались).

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

ПЕРЕВОД
       Copyright (C) Alexey Mahotkin <alexm@hsys.msk.ru> 1999-2001



Linux 2.2                          7 May 1999                          ACCEPT(2)