table of contents
- bookworm 4.18.1-1
- bookworm-backports 4.24.0-2~bpo12+1
- testing 4.24.0-2
- unstable 4.24.0-2
accept(2) | System Calls Manual | accept(2) |
НАИМЕНОВАНИЕ¶
accept, accept4 - принять соединение через сокет
БИБЛИОТЕКА¶
Стандартная библиотека С (libc, -lc)
ОБЗОР¶
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *_Nullable restrict addr, socklen_t *_Nullable restrict addrlen);
#define _GNU_SOURCE /* Смотрите feature_test_macros(7) */ #include <sys/socket.h>
int accept4(int sockfd, struct sockaddr *_Nullable restrict addr, socklen_t *_Nullable restrict 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 статуса файла на открытие файлового дескриптора, на который ссылается новый файловый дескриптор (смотрите open(2)). Использование данного флага делает ненужными дополнительные вызовы fcntl(2) для получения того же результата.
- SOCK_CLOEXEC
- Устанавливает флаг завершение выполнения (FD_CLOEXEC) для нового открытого файлового дескриптора. Смотрите описание флага O_CLOEXEC в open(2) для того, чтобы узнать для чего это может пригодиться.
ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ¶
При успешном выполнении эти системные вызовы возвращают файловый дескриптор для принятого сокета (неотрицательное целое число). В случае ошибки возвращается -1, errno, которое является сообщением об ошибке, а значение addrlen не изменяется.
Обработка ошибок¶
В реализации 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.
- EPERM
- Правила межсетевого экрана запрещают соединение.
- EPROTO
- Ошибка протокола.
Кроме того, могут быть возвращены сетевые ошибки для нового сокета и в соответствии с определениями протокола. Различные ядра Linux могут возвращать другие ошибки, например, ENOSR, ESOCKTNOSUPPORT, EPROTONOSUPPORT, ETIMEDOUT. Значение ошибки ERESTARTSYS можно увидеть при трассировке.
ВЕРСИИ¶
Системный вызов accept4() доступен, начиная с Linux 2.6.28; поддержка в glibc доступна, начиная с glibc 2.10.
СТАНДАРТЫ¶
accept(): POSIX.1-2001, POSIX.1-2008, SVr4, 4.4BSD, (accept() впервые появился в 4.2BSD).
accept4() является нестандартным дополнением Linux.
В Linux новый сокет, возвращаемый accept(), not не наследует флагов состояния файла, таких как O_NONBLOCK и O_ASYNC из прослушивающего сокета. Это поведение отличается от канонической реализации сокетов BSD. Переносимые программы не должны полагаться на наследование флагов состояния файла или их отсутствие, а всегда должны устанавливать на сокете, полученном от accept(), все требуемые флаги.
ПРИМЕЧАНИЯ¶
После доставки SIGIO не всегда может быть установлено ожидающее соединение или select(2), poll(2) или epoll(7) вернут событие доступности чтения, так как подключение может быть удалено из-за асинхронной сетевой ошибкой или другой поток был вызван раньше accept(). Если это случилось, то вызов блокируется, ожидая прибытия следующего подключения. Чтобы гарантировать, что функция accept() никогда не блокируется, для переданного сокета sockfd должен быть установлен флаг O_NONBLOCK (см. socket(7)).
Для определённых протоколов, которые требуют явного подтверждения, например, DECnet, accept() можно рассматривать просто как извлечение из очереди следующего запроса на соединение, не подразумевающее подтверждения. Подтверждение, в свою очередь, произойдет при следующем чтении или записи в новом файловом дескрипторе, а отказ от соединения может произойти при закрытии нового сокета. В настоящее время, под Linux такую семантику имеет только DECnet.
Тип socklen_t¶
В первоначальной реализации сокетов в BSD (и в других системах) третий аргумент accept() объявлялся как int *. В стандарте черновика POSIX.1g захотели изменить его на size_t *. В поздних версиях стандарта POSIX и в glibc 2.x используется socklen_t *.
ПРИМЕРЫ¶
См. bind(2).
СМОТРИТЕ ТАКЖЕ¶
bind(2), connect(2), listen(2), select(2), socket(2), socket(7)
ПЕРЕВОД¶
Русский перевод этой страницы руководства разработал(и) Dmitry Bolkhovskikh <d20052005@yandex.ru>, Yuri Kozlov <yuray@komyakino.ru> и Aleksandr Felda <isk8da@gmail.com>
Этот перевод является свободной программной документацией; он распространяется на условиях общедоступной лицензии GNU (GNU General Public License - GPL, https://www.gnu.org/licenses/gpl-3.0.html версии 3 или более поздней) в отношении авторского права, но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ.
Если вы обнаружите какие-либо ошибки в переводе этой страницы руководства, пожалуйста, сообщите об этом разработчику(ам) по его(их) адресу(ам) электронной почты или по адресу списка рассылки русских переводчиков.
2022-12-04 | Страницы руководства Linux 6.03 |