Provided by: manpages-ru-dev_4.18.1-1_all bug

ИМЯ

       recvmmsg - получает несколько сообщений из сокета

LIBRARY

       Standard C library (libc, -lc)

СИНТАКСИС

       #define _GNU_SOURCE         /* Смотрите feature_test_macros(7) */
       #include <sys/socket.h>

       int recvmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen,
                    int flags, struct timespec *timeout);

ОПИСАНИЕ

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

       Аргумент sockfd представляет собой файловый дескриптор сокета приёма данных.

       Аргумент msgvec является указателем на  массив  структур  mmsghdr.  Размер  этого  массива
       указывается в vlen.

       Структура mmsghdr определена в <sys/socket.h> следующим образом:

           struct mmsghdr {
               struct msghdr msg_hdr;  /* Заголовок сообщения */
               unsigned int  msg_len;  /* Количество полученных байт
                                          для заголовка */
           };

       Поле  msg_hdr  представляет  собой  структуру msghdr, которая описана в recvmsg(2). В поле
       msg_len содержится количество байт возвращаемого сообщения в записи. Это поле имеет  такое
       же значение, что и возвращаемое значение одиночного вызова recvmsg(2) в заголовке.

       Аргумент  flags содержит объединённые с помощью OR флаги. Флаги те же, что и у recvmsg(2),
       но со следующим дополнением:

       MSG_WAITFORONE (начиная с Linux 2.6.34)
              Включить MSG_DONTWAIT после получения первого сообщения.

       Аргумент timeout указывает на struct timespec (смотрите clock_gettime(2)), задающую  время
       ожидания (в секундах и наносекундах) операции приёма (но смотрите ДЕФЕКТЫ!; (этот интервал
       будет округлён до точности системных часов, и из-за задержек  планировщика  ядра  интервал
       блокировки может быть немного больше). Если timeout равно NULL, то операция блокируется на
       неопределённое время.

       Блокирование вызова recvmmsg()  происходит  до  тех  пор,  пока  не  будет  получено  vlen
       сообщений  или  не  истечёт  интервал блокировки. Неблокирующий вызов читает все доступные
       сообщения (максимальное количество указано в vlen) и сразу завершает работу.

       При выходе из recvmmsg() последующие элементы  msgvec  обновляются  информацией  о  каждом
       полученном  сообщении:  в  msg_len  содержится размер принятого сообщения; подполя msg_hdr
       обновляются  согласно  описанию  в  recvmsg(2).  Возвращаемое  значение  вызова   означает
       количество обновлённых элементов msgvec.

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

       При  успешном выполнении recvmmsg() возвращает количество принятых в msgvec сообщений; при
       ошибке возвращается -1 и в errno устанавливается код ошибки.

ОШИБКИ

       Возникают те же ошибки что и для recvmsg(2). Кроме этого, случается следующая ошибка:

       EINVAL Значение timeout неверно.

       Также смотрите ДЕФЕКТЫ.

ВЕРСИИ

       The recvmmsg()  system call was added in Linux 2.6.33.  Support  in  glibc  was  added  in
       glibc 2.12.

СТАНДАРТЫ

       Вызов recvmmsg() есть только в Linux.

ДЕФЕКТЫ

       Аргумент  timeout  работает  не  так, как планировалось. Время ожидания проверяется только
       после приёма каждой дейтаграммы, поэтому, если до истечения срока будет получено до vlen-1
       дейтаграмм, но затем дейтаграммы не поступят, то вызов заблокируется навсегда.

       Если  ошибка  возникает  после  получения  хотя  бы одного сообщения, то вызов выполняется
       успешно и  возвращается  количество  полученных  сообщений.  Код  ошибки  будет  возвращён
       следующим  вызовом recvmmsg(). Однако в текущей реализации код ошибки может перезаписаться
       при  возникновении  в  тоже  время  события,  не  связанного  с  сетью,  например,   из-за
       поступившего пакета ICMP.

ПРИМЕРЫ

       Следующая программа использует recvmmsg() для получения нескольких сообщений через сокет и
       сохранения их в несколько буферов. Вызов завершается при заполнении всех буферов, либо  по
       окончании заданного временного интервала.

       Следующий отрывок периодически генерирует датаграммы UDP с произвольным номером внутри:

           $ while true; do echo $RANDOM > /dev/udp/127.0.0.1/1234;
           sleep 0.25; done

       Эти датаграммы читаются примером приложения, который выдаёт:

           $ ./a.out
           5 сообщений получено
           1 11782
           2 11345
           3 304
           4 13514
           5 28421

   Исходный код программы

       #define _GNU_SOURCE
       #include <arpa/inet.h>
       #include <netinet/in.h>
       #include <stdio.h>
       #include <stdlib.h>
       #include <string.h>
       #include <sys/socket.h>
       #include <time.h>

       int
       main(void)
       {
       #define VLEN 10
       #define BUFSIZE 200
       #define TIMEOUT 1
           int                 sockfd, retval;
           char                bufs[VLEN][BUFSIZE+1];
           struct iovec        iovecs[VLEN];
           struct mmsghdr      msgs[VLEN];
           struct timespec     timeout;
           struct sockaddr_in  addr;

           sockfd = socket(AF_INET, SOCK_DGRAM, 0);
           if (sockfd == -1) {
               perror("socket()");
               exit(EXIT_FAILURE);
           }

           addr.sin_family = AF_INET;
           addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
           addr.sin_port = htons(1234);
           if (bind(sockfd, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
               perror("bind()");
               exit(EXIT_FAILURE);
           }

           memset(msgs, 0, sizeof(msgs));
           for (size_t i = 0; i < VLEN; i++) {
               iovecs[i].iov_base         = bufs[i];
               iovecs[i].iov_len          = BUFSIZE;
               msgs[i].msg_hdr.msg_iov    = &iovecs[i];
               msgs[i].msg_hdr.msg_iovlen = 1;
           }

           timeout.tv_sec = TIMEOUT;
           timeout.tv_nsec = 0;

           retval = recvmmsg(sockfd, msgs, VLEN, 0, &timeout);
           if (retval == -1) {
               perror("recvmmsg()");
               exit(EXIT_FAILURE);
           }

           printf("%d messages received\n", retval);
           for (size_t i = 0; i < retval; i++) {
               bufs[i][msgs[i].msg_len] = 0;
               printf("%zu %s", i+1, bufs[i]);
           }
           exit(EXIT_SUCCESS);
       }

СМ. ТАКЖЕ

       clock_gettime(2), recvmsg(2), sendmmsg(2), sendmsg(2), socket(2), socket(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>

       Этот  перевод  является  бесплатной  документацией;  прочитайте  Стандартную  общественную
       лицензию GNU версии 3 ⟨https://www.gnu.org/licenses/gpl-3.0.html⟩ или более позднюю, чтобы
       узнать об условиях авторского права. Мы не несем НИКАКОЙ ОТВЕТСТВЕННОСТИ.

       Если вы обнаружите ошибки в переводе  этой  страницы  руководства,  пожалуйста,  отправьте
       электронное письмо на ⟨man-pages-ru-talks@lists.sourceforge.net⟩.