| accept(2) | System Calls Manual | accept(2) |
accept, accept4 - принять соединение через сокет
Стандартная библиотека языка C (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 может быть применена операция поразрядного логического ИЛИ для получения различного поведения:
При успешном выполнении эти системные вызовы возвращают файловый дескриптор для принятого сокета (неотрицательное целое число). В случае ошибки возвращается -1, errno, которое является сообщением об ошибке, а значение addrlen не изменяется.
В реализации Linux accept() (и accept4()) передаёт уже ожидающие сетевые ошибки на новый сокет, как код ошибки из вызова accept(). Это поведение отличается от других реализаций BSD-сокетов. Для надёжной работы приложения должны отслеживать сетевые ошибки, которые могут появиться при работе accept() с протоколом и обрабатывать их как EAGAIN повторно выполняя вызов. В случае TCP/IP такими ошибками являются ENETDOWN, EPROTO, ENOPROTOOPT, EHOSTDOWN, ENONET, EHOSTUNREACH, EOPNOTSUPP и ENETUNREACH.
Кроме того, могут быть возвращены сетевые ошибки для нового сокета и в соответствии с определениями протокола. Различные ядра Linux могут возвращать другие ошибки, например, ENOSR, ESOCKTNOSUPPORT, EPROTONOSUPPORT, ETIMEDOUT. Значение ошибки ERESTARTSYS можно увидеть при трассировке.
В 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.
В первоначальной реализации сокетов в 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> и Kirill Rekhov <krekhov.dev@gmail.com>
Этот перевод является свободной программной документацией; он распространяется на условиях общедоступной лицензии GNU (GNU General Public License - GPL, https://www.gnu.org/licenses/gpl-3.0.html версии 3 или более поздней) в отношении авторского права, но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ.
Если вы обнаружите какие-либо ошибки в переводе этой страницы руководства, пожалуйста, сообщите об этом разработчику(ам) по его(их) адресу(ам) электронной почты или по адресу списка рассылки русских переводчиков.
| 2 мая 2024 г. | Справочные страницы Linux 6.9.1 |