...

Accept что это за программа

4.6. Функция accept

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

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

Возвращает: неотрицательный дескриптор в случае успешного выполнения функции, -1 в случае ошибки

Аргументы cliaddr и addrlen используются для возвращения адреса протокола подключившегося процесса (клиента). Аргумент addrlen — это аргумент типа «значение-результат» (см. раздел 3.3). Перед вызовом мы присваиваем целому числу, на которое указывает *addrlen, размер структуры адреса сокета, на которую указывает аргумент cliaddr, и по завершении функции это целое число содержит действительное число байтов, помещенных ядром в структуру адреса сокета.

Если выполнение функции accept прошло успешно, она возвращает новый дескриптор, автоматически созданный ядром. Этот дескриптор используется для обращения к соединению TCP с конкретным клиентом. При описании функции accept мы называем ее первый аргумент прослушиваемым сокетом (listening socket) (дескриптор, созданный функцией socket и затем используемый в качестве аргумента для функций bind и listen), а значение, возвращаемое этой функцией, мы называем присоединенным сокетом (connected socket). Сервер обычно создает только один прослушиваемый сокет, который существует в течение всего времени жизни сервера. Затем ядро создает по одному присоединенному сокету для каждого клиентского соединения, принятого с помощью функции accept (для которого завершено трехэтапное рукопожатие TCP). Когда сервер заканчивает предоставление сервиса данному клиенту, сокет закрывается.

Эта функция возвращает до трех значений: целое число, которое является либо дескриптором сокета, либо кодом ошибки, а также адрес протокола клиентского процесса (через указатель cliaddr) и размер адреса (через указатель addrlen). Если нам не нужно, чтобы был возвращен адрес протокола клиента, следует сделать указатели cliaddr и addrlen пустыми указателями.

В листинге 1.5 показаны эти моменты. Присоединенный сокет закрывается при каждом прохождении цикла, но прослушиваемый сокет остается открытым в течение времени жизни сервера. Мы также видим, что второй и третий аргументы функции accept являются пустыми указателями, поскольку нам не нужно идентифицировать клиент.

Данный текст является ознакомительным фрагментом.

Продолжение на ЛитРес

Читайте также

5.11. Прерывание соединения перед завершением функции accept

5.11. Прерывание соединения перед завершением функции accept Существует другое условие, аналогичное прерванному системному вызову, пример которого был описан в предыдущем разделе. Оно может привести к возвращению функцией accept нефатальной ошибки, в случае чего следует

16.6. Неблокируемая функция accept

16.6. Неблокируемая функция accept Как было сказано в главе 6, функция select сообщает, что прослушиваемый сокет готов для чтения, когда установленное соединение готово к обработке функцией accept. Следовательно, если мы используем функцию select для определения готовности входящих

30.6. Сервер TCP с предварительным порождением процессов без блокировки для вызова accept

30.6. Сервер TCP с предварительным порождением процессов без блокировки для вызова accept В первом из рассматриваемых нами «усовершенствованных» серверов используется технология, называемая предварительным созданием процессов (preforking). Вместо того чтобы вызывать функцию fork

30.7. Сервер TCP с предварительным порождением процессов и защитой вызова accept блокировкой файла

30.7. Сервер TCP с предварительным порождением процессов и защитой вызова accept блокировкой файла Описанная выше реализация, позволяющая нескольким процессам вызывать функцию accept на одном и том же прослушиваемом дескрипторе, возможна только для систем 4.4BSD, в которых функция

30.8. Сервер TCP с предварительным порождением процессов и защитой вызова accept при помощи взаимного исключения

30.8. Сервер TCP с предварительным порождением процессов и защитой вызова accept при помощи взаимного исключения Как мы уже говорили, существует несколько способов синхронизации процессов путем блокирования. Блокировка файла по стандарту POSIX, рассмотренная в предыдущем

30.11. Сервер TCP с предварительным порождением потоков, каждый из которых вызывает accept

30.11. Сервер TCP с предварительным порождением потоков, каждый из которых вызывает accept Ранее в этой главе мы обнаружили, что версии, в которых заранее создается пул дочерних процессов, работают быстрее, чем те, в которых для каждого клиентского запроса приходится вызывать

30.12. Сервер с предварительным порождением потоков: основной поток вызывает функцию accept

30.12. Сервер с предварительным порождением потоков: основной поток вызывает функцию accept Последняя рассматриваемая нами версия сервера устроена следующим образом: главный поток создает пул потоков при запуске сервера, после чего он же вызывает функцию accept и передает

6.5.1. Действие ACCEPT

6.5.1. Действие ACCEPT Данная операция не имеет дополнительных ключей. Если над пакетом выполняется действие ACCEPT, то пакет прекращает движение по цепочке (и всем вызвавшим цепочкам, если текущая цепочка была вложенной) и считается ПРИНЯТЫМ (то бишь пропускается), тем не менее,

Функция SUM

Функция SUM Ваши возможности в подведении итогов не ограничены простым подсчетом записей. Используя функцию SUM, можно генерировать итоговые результаты для всех возвращаемых записей по любым числовым полям. Например, для создания запроса, который генерирует итоги по

Функция uni()

Функция uni() Поиск/замена символа по его юникодному номеру также может быть сделана при помощи функции uni().Пример функции uni(): Boouni(107,32)Designer найдет слово Book

Хэш-функция.

Хэш-функция. Еще одно важное преимущество использования PGP состоит в том, что PGP применяет так называемую «хэш-функцию», которая действует таким образом, что в том случае какого-либо изменения информации, пусть даже на один бит, результат «хэш-функции» будет совершенно

Функция uni()

Функция uni() Поиск/замена символа по его юникодному номеру также может быть сделана при помощи функции uni().Пример функции uni(): Boouni(107,32)Designer найдет слово Book

Accept что это за программа

#include /* См. ЗАМЕЧАНИЯ */
#include
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
#define _GNU_SOURCE /* Смотрите feature_test_macros(7) */
#include
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). В этом случае, когда придёт запрос на новое соединение, будет доставлено событие “можно читать”, и после этого вы можете вызвать accept() чтобы получить сокет для этого соединения. Можно также настроить сокет так, чтобы он посылал сигнал SIGIO, когда на нём происходит какая-либо активность; см. socket(7). Для определённых протоколов, которые требуют явного подтверждения, например, DECNet, accept() можно рассматривать просто как извлечение из очереди следующего запроса на соединение, не подразумевающее подтверждение. Подтверждение, в свою очередь, произойдет при следующем чтении или записи в новом файловом дескрипторе, а отказ от соединения может произойти при закрытии нового сокета. В настоящее время, под Linux такую семантику имеет только DECNet. Если 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 не требуется включение , и этот заголовочный файл не требуется в Linux. Однако, некоторые старые (BSD) реализации требуют данный файл, и в переносимых приложениях для предосторожности, вероятно, он будет включён. Возможно не всегда будет ожидание подключения после доставки SIGIO; или select(2) или poll(2) вернут событие доступности чтения, так как подключение может быть удалено из-за асинхронной сетевой ошибкой или другая нить была вызвала раньше accept(). Это это случается, то вызов блокируется, ожидая следующего прибытия подключения. Чтобы быть уверенным, что accept() никогда не заблокируется, сокету sockfd необходимо установить флаг O_NONBLOCK (см. socket(7)).

Тип 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”. Вообще, с самого начала они просто не должны были ничего трогать, но по какой-то причине они чувствовали, что должны использовать именованный тип (вероятно, они не хотели ударить в грязь лицом сделав глупость, поэтому они тихо переименовали место, в котором просчитались).”

24. Функция accept

Как уже отмечалось, функция bind привязывает сетевой адрес и номер локального порта протокола к определенному сокету. Программы-клиенты устанавливают соединение, привязывая сокет к удаленному порту протокола, расположенному на удаленном компьютере. Клиент знает, какой именно сервер ему нужен, Поэтому располагает всей требуемой информацией.

С другой стороны, сервер не имеет представления о том, от какого клиента •может поступить запрос. Поэтому, вызвав bind, он не может определить заранее ни его адреса, ни номера порта. Вместо этого сервер вызывает bind, задав в качестве аргумента символ, совпадающий с любым адресом (wildcard). Константа, определяющая любой адрес, называется INADDR_ANY. Другими словами, такой сервер принимает запросы от любого сетевого компьютера, то есть от любой программы-клиента.

Как следует из названия, функция accept позволяет серверу принять запрос на соединение, поступивший от клиента. После того как установлена входная очередь, программа-сервер вызывает функцию accept и переходит в режим ожидания (паузы), ожидая запросов. Для того чтобы понять смысл всех операций сервера, мы должны подробно рассмотреть, как функционирует accept.

При вызове accept требуется указывать три параметра: дескриптор сокета, его адрес и длину адреса. Дескриптор сокета описывает сокет, который будет прослушиваться сервером. В момент появления запроса реализация сокетов заполняет структуру адреса (на которую указывает второй параметр) адресом клиента, от которого поступил запрос.

Реализация сокетов заполняет также третий параметр, размещая в нем длину адреса. Следующий оператор демонстрирует, как можно вызывать функцию accept:

result = accept (socket_handle, socket_address, address_length);

После того как реализация сокетов поместит информацию об адресе клиента в область памяти, заданную параметром функции, она выполнит операции, необходимые для того, чтобы сервер заработал. Первым делом, получив запрос соединения на сокет, обслуживаемый функцией accept, реализация образует новый сокет. Новый сокет связывается с адресом процесса-передатчика запроса. На рис. 6 изображена ситуация, когда два клиента обращаются к серверу параллельной обработки запросов.

Коротко весь процесс можно описать следующим образом: когда на сокете, контролируемом функцией accept, появляется очередной запрос клиента, программное обрспечение-реализация сокетов автоматически создает новый сокет и немедленно соединяет его с процессом-клиентом. Сокет, на который поступил запрос, освобождается и продолжает работу в режиме ожидания запросов от любого сетевого компьютера.

25. Процесс-сервер

Как только на сокете, обслуживаемом функцией accept, появляется запрос, функция возвращает серверу дескриптор только что созданного нового сокета. Что сервер будет делать с этим дескриптором, зависит от реализации сервера. Сервер может обрабатывать запросы параллельно или последовательно. Предположим, что вы создали последовательный сервер. Следовательно, он будет последовательно обрабатывать, а затем закрывать все переданные ему функцией accept дескрипторы сокетов. По окончании обработки конкретного запроса последовательный сервер вновь вызывает accept, а она возвращает ему дескриптор сокета для следующего запроса, если он имеется, и т. д. Если до этого вызывалась функция listen, запрос может быть выбран из входной очереди, если нет — сервер прослушивает сетевые запросы напрямую через сокет.

Теперь предположим, что вы написали сервер параллельной обработки. После того как выполнится функция accept, параллельный сервер создаст новый (дочерний) процесс и передаст ему задачу по обслуживанию нового запроса. Каким образом создается дочерний процесс, зависит от операционной системы. В UNIX, например, для этого вызывается функция fork. Независимо от того, как создается дочерний процесс, процесс-родитель передает ему копию нового сокета. Далее родительский процесс закрывает собственную копию сокета и вновь вызывает функцию accept.

Можно видеть, что и последовательный и параллельный серверы действуют практически одинаково, обслуживая сетевые запросы. Между ними существует лишь одно различие: параллельный сервер не ждет, пока закончится обработка запроса, а вызывает функцию accept сразу же. Последовательный сервер не может вызвать accept до тех пор, пока не обработает запрос. Программа-сервер с параллельной обработкой запросов создает дочерний процесс для обработки поступающих запросов и сразу после этого вызывает функцию accept. За исключением случаев, когда обработка запроса почти не занимает времени, сервер успевает вызвать accept еще до того, как дочерний процесс ее закончит. Другими словами, сервер параллельной обработки запросов способен отвечать на множество запросов одновременно.

При подготовке материала использовались источники:
https://it.wikireading.ru/7015
https://ru.manpages.org/accept/2
https://studfile.net/preview/1174761/page:12/

Добавить комментарий