recv(2) System Calls Manual recv(2)

НАИМЕНОВАНИЕ

recv, recvfrom, recvmsg - принимает сообщение из сокета

БИБЛИОТЕКА

Standard C library (libc-lc)

ОБЗОР

#include <sys/socket.h>
ssize_t recv(int sockfd, void buf[.size], size_t size,
                 int flags);
ssize_t recvfrom(int sockfd, void buf[restrict .size], size_t size,
                 int flags,
                 struct sockaddr *_Nullable restrict src_addr,
                 socklen_t *_Nullable restrict addrlen);
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

ОПИСАНИЕ

Системные вызовы recv(), recvfrom() и recvmsg() используются для получения сообщений из сокета. Они могут использоваться для получения данных, независимо от того, является ли сокет ориентированным на соединения или нет. В этой странице сперва описаны общие свойства всех трёх системных вызовов, а затем описываются различия между ними.

Вызов recv() отличается от read(2) только наличием аргумента flags. Если значение flags равно нулю, то вызов recv() эквивалентен read(2) (но смотрите ЗАМЕЧАНИЯ). Также, вызов


recv(sockfd, buf, size, flags);

равнозначно


recvfrom(sockfd, buf, size, flags, NULL, NULL);

All three calls return the size of the message on successful completion. If a message is too long to fit in the supplied buffer, excess bytes may be discarded depending on the type of socket the message is received from.

If no messages are available at the socket, the receive calls wait for a message to arrive, unless the socket is nonblocking (see fcntl(2)), in which case the value -1 is returned and errno is set to EAGAIN or EWOULDBLOCK. The receive calls normally return any data available, up to the requested amount, rather than waiting for receipt of the full amount requested.

Для определения появления новых данных в сокете приложение может использовать select(2), poll(2) или epoll(7).

Аргумент флагов

Аргумент flags формируется с помощью объединения логической операцией ИЛИ одного или более следующих значений:

Установить флаг close-on-exec для файлового дескриптора, полученного через доменный файловый дескриптор UNIX, с помощью операции SCM_RIGHTS (описана в unix(7)). Этот флаг полезен по тем же причинам что и флаг O_CLOEXEC у open(2).
Enables nonblocking operation; if the operation would block, the call fails with the error EAGAIN or EWOULDBLOCK. This provides similar behavior to setting the O_NONBLOCK flag (via the fcntl(2) F_SETFL operation), but differs in that MSG_DONTWAIT is a per-call option, whereas O_NONBLOCK is a setting on the open file description (see open(2)), which will affect all threads in the calling process as well as other processes that hold file descriptors referring to the same open file description.
Указание этого флага позволяет получить из очереди ошибок сокета накопившиеся ошибки. Ошибка передаётся в вспомогательном сообщении тип которого зависит от протокола (для IPv4 это IP_RECVERR). Вызывающий должен предоставить буфер достаточного размера. Дополнительная информация приведена в cmsg(3) и ip(7). Содержимое исходного пакета, который привёл к ошибке, передаётся в виде обычных данных через msg_iovec. Исходный адрес назначения датаграммы, которая привела к ошибке, передаётся через msg_name.
Ошибка передаётся в виде структуры sock_extended_err:

#define SO_EE_ORIGIN_NONE    0
#define SO_EE_ORIGIN_LOCAL   1
#define SO_EE_ORIGIN_ICMP    2
#define SO_EE_ORIGIN_ICMP6   3
struct sock_extended_err
{
    uint32_t ee_errno;   /* Error number */
    uint8_t  ee_origin;  /* Where the error originated */
    uint8_t  ee_type;    /* Type */
    uint8_t  ee_code;    /* Code */
    uint8_t  ee_pad;     /* Padding */
    uint32_t ee_info;    /* Additional information */
    uint32_t ee_data;    /* Other data */
    /* More data may follow */
};
struct sockaddr *SO_EE_OFFENDER(struct sock_extended_err *);

В ee_errno содержится значение errno для ожидающей ошибки. В ee_origin содержится источник происхождения ошибки. Смысл остальных полей зависит от протокола. Макрос SO_EE_OFFENDER возвращает указатель на адрес сетевого объекта, породившего ошибку. Если этот адрес неизвестен, то поле sa_family структуры sockaddr содержит значение AF_UNSPEC, а прочие поля структуры sockaddr не определены. Содержимое пакета, вызвавшего ошибку, передаётся в виде обычных данных.
Для локальных ошибок адрес не передаётся (это можно выяснить, проверив поле cmsg_len структуры cmsghdr). Для ошибок при приёме устанавливается флаг MSG_ERRQUEUE в msghdr. После того, как ошибка передана программе, следующая ошибка в очереди ошибок становится ожидающей ошибкой и передается программе при следующей операции на сокете.
Этот флаг запрашивает приём внеполосных данных, которые в противном случае не были бы получены в обычном потоке данных. Некоторые протоколы помещают данные повышенной срочности в начало очереди с обычными данными, и поэтому этот флаг не может использоваться с такими протоколами.
Этот флаг заставляет выбрать данные из начала очереди приёма, но не удалять их оттуда. Таким образом, последующий вызов вернёт те же самые данные.
For raw (AF_PACKET), Internet datagram (since Linux 2.4.27/2.6.8), netlink (since Linux 2.6.22), and UNIX datagram as well as sequenced-packet (since Linux 3.4) sockets: return the real size of the packet or datagram, even when it was longer than the passed buffer.
Описание использования с потоковым сокетами Интернета смотрите в tcp(7).
Этим флагом включается блокирование операции до полной обработки запроса. Однако, этот вызов всё равно может вернуть меньше данных, чем было запрошено, если был пойман сигнал, произошла ошибка или разрыв соединения, или если начали поступать данные другого типа, не того, который был сначала. Этот флаг не влияет на датаграммные сокеты.

recvfrom() places the received message into the buffer buf. The caller must specify the size of the buffer in size.

Если значение src_addr не равно NULL, и в нижележащем протоколе используется адрес источника сообщения, то адрес источника помещается в буфер, указанный в src_addr. В этом случае addrlen является аргументом-результатом. Перед вызовом ему должно быть присвоено значение длины буфера, связанного с src_addr. При возврате addrlen обновляется и содержит действительный размер адреса источника. Возвращаемый адрес обрезается, если предоставленный буфер слишком мал; в этом случае addrlen будет содержать значение большее, чем указывалось в вызове.

Если вызывающему адрес источника не нужен, то значение src_addr и addrlen должно быть равно NULL.

Вызов recv(), обычно, используется только на соединённом сокете (смотрите connect(2)). Он идентичен вызову:


recvfrom(fd, buf, size, flags, NULL, 0);

Для минимизации количества передаваемых аргументов в вызов recvmsg() используется структура msghdr. Она определена в <sys/socket.h> следующим образом:


struct msghdr {
    void         *msg_name;       /* Optional address */
    socklen_t     msg_namelen;    /* Size of address */
    struct iovec *msg_iov;        /* Scatter/gather array */
    size_t        msg_iovlen;     /* # elements in msg_iov */
    void         *msg_control;    /* Ancillary data, see below */
    size_t        msg_controllen; /* Ancillary data buffer size */
    int           msg_flags;      /* Flags on received message */
};

The msg_name field points to a caller-allocated buffer that is used to return the source address if the socket is unconnected. The caller should set msg_namelen to the size of this buffer before this call; upon return from a successful call, msg_namelen will contain the size of the returned address. If the application does not need to know the source address, msg_name can be specified as NULL.

В полях msg_iov и msg_iovlen описываются место приёма/передачи, обсуждаемые в readv(2).

The field msg_control, which has size msg_controllen, points to a buffer for other protocol control-related messages or miscellaneous ancillary data. When recvmsg() is called, msg_controllen should contain the size of the available buffer in msg_control; upon return from a successful call it will contain the size of the control message sequence.

Сообщения имеют следующий вид:


struct cmsghdr {
    size_t cmsg_len;    /* счетчик байтов данных с заголовком
                           (тип — socklen_t в POSIX) */
    int    cmsg_level;  /* начальный протокол */
    int    cmsg_type;   /* тип, зависящий от протокола */
/* после
   unsigned char cmsg_data[]; */
};

К вспомогательным данным нужно обращаться только с помощью макросов, определённых в cmsg(3).

As an example, Linux uses this ancillary data mechanism to pass extended errors, IP options, or file descriptors over UNIX domain sockets. For further information on the use of ancillary data in various socket domains, see unix(7) and ip(7).

При возврате из recvmsg() устанавливается значение поля msg_flags в msghdr. Оно может содержать несколько флагов:

означает конец записи: возвращённые данные заканчивают запись (обычно используется вместе с сокетами типа SOCK_SEQPACKET).
означает, что хвостовая часть датаграммы была отброшена, потому что датаграмма была больше, чем предоставленный буфер.
означает, что часть управляющих данных была отброшена из-за недостатка места в буфере вспомогательных данных.
возвращается для индикации, что получены курируемые или внеполосные данные.
означает, что были получены не данные, а расширенное сообщение об ошибке из очереди ошибок сокета.
indicates that MSG_CMSG_CLOEXEC was specified in the flags argument of recvmsg().

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ

Эти вызовы возвращают количество принятых байт или -1, если произошла ошибка. В случае ошибки в errno записывается код ошибки.

Когда ответная сторона потока выполняет корректное отключение (shutdown), то возвращается 0 (обычный возврат «конец файла»).

Datagram sockets in various domains (e.g., the UNIX and Internet domains) permit zero-size datagrams. When such a datagram is received, the return value is 0.

Также значение 0 может возвращаться, если запрошенное количество принимаемых байт из потокового сокета равно 0.

ОШИБКИ

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

Сокет помечен как неблокируемый, а операция приёма привела бы к блокировке, или установлено время ожидания данных и это время истекло до получения данных. Согласно POSIX.1 в этом случае может возвращаться любая ошибка и не требуется, чтобы эти константы имели одинаковое значение, поэтому переносимое приложение должно проверить оба случая.
Аргумент sockfd содержит неверный файловый дескриптор.
Удалённый узел отказался устанавливать сетевое соединение (обычно потому, что там не работает запрошенная служба).
Указатель на приёмный буфер указывает вне адресного пространства процесса.
Приём данных был прерван сигналом, а данные ещё не были доступны; смотрите signal(7).
Передан неверный аргумент.
Не удалось выделить память для recvmsg().
Сокет, связанный с протоколом, ориентированным на соединение, не был соединён (см. connect(2) и accept(2)).
Файловый дескриптор sockfd указывает не на каталог.

ВЕРСИИ

According to POSIX.1, the msg_controllen field of the msghdr structure should be typed as socklen_t, and the msg_iovlen field should be typed as int, but glibc currently types both as size_t.

СТАНДАРТЫ

POSIX.1-2008.

ИСТОРИЯ

POSIX.1-2001, 4.4BSD (впервые появились в 4.2BSD).

В POSIX.1 описаны только флаги MSG_OOB, MSG_PEEK и MSG_WAITALL.

ПРИМЕЧАНИЯ

If a zero-size datagram is pending, read(2) and recv() with a flags argument of zero provide different behavior. In this circumstance, read(2) has no effect (the datagram remains pending), while recv() consumes the pending datagram.

В recvmmsg(2) можно найти информацию о специальном системном вызове Linux, который можно использовать для приёма нескольких датаграмм за один вызов.

ПРИМЕРЫ

Пример использования recvfrom() показан в getaddrinfo(3).

СМОТРИТЕ ТАКЖЕ

fcntl(2), getsockopt(2), read(2), recvmmsg(2), select(2), shutdown(2), socket(2), cmsg(3), sockatmark(3), ip(7), ipv6(7), socket(7), tcp(7), udp(7), unix(7)

ПЕРЕВОД

Русский перевод этой страницы руководства разработал(и) aereiae <aereiae@gmail.com>, Azamat Hackimov <azamat.hackimov@gmail.com>, Dmitriy S. Seregin <dseregin@59.ru>, Katrin Kutepova <blackkatelv@gmail.com>, Lockal <lockalsash@gmail.com>, Yuri Kozlov <yuray@komyakino.ru>, Баринов Владимир, Иван Павлов <pavia00@gmail.com> и Kirill Rekhov <krekhov.dev@gmail.com>

Этот перевод является свободной программной документацией; он распространяется на условиях общедоступной лицензии GNU (GNU General Public License - GPL, https://www.gnu.org/licenses/gpl-3.0.html версии 3 или более поздней) в отношении авторского права, но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ.

Если вы обнаружите какие-либо ошибки в переводе этой страницы руководства, пожалуйста, сообщите об этом разработчику(ам) по его(их) адресу(ам) электронной почты или по адресу списка рассылки русских переводчиков.

17 ноября 2024 г. Linux man-pages 6.12