accept, accept4 - принять
соединение
на сокете
Standard C library (
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
- Устанавливает
флаг close-on-exec ( FD_CLOEXEC)
для нового
открытого
файлового
дескриптора.
Смотрите
описание
флага O_CLOEXEC в
open(2) для того,
чтобы
узнать как
это может
пригодиться.
On success, these system calls return a file descriptor for the accepted socket
(a nonnegative integer). On error, -1 is returned,
errno is set to
indicate the error, and
addrlen is left unchanged.
В
реализации
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
можно
увидеть
при
трассировке.
The
accept4() system call is available starting with Linux 2.6.28;
support in glibc is available starting with 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(), все
требуемые
флаги.
Возможно
не всегда
будет
ожидание
подключения
после
доставки
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 <
[email protected]> и Yuri Kozlov
<
[email protected]>
Этот
перевод
является
бесплатной
документацией;
прочитайте
Стандартную
общественную
лицензию GNU
версии 3
или более
позднюю,
чтобы
узнать об
условиях
авторского
права. Мы не
несем
НИКАКОЙ
ОТВЕТСТВЕННОСТИ.
Если вы
обнаружите
ошибки в
переводе
этой
страницы
руководства,
пожалуйста,
отправьте
электронное
письмо на
[email protected]