ИМЯ
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 после получения первого сообщения.
ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При успешном выполнении 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 <[email protected]>, Azamat Hackimov <[email protected]>, Dmitriy S. Seregin <[email protected]>, Katrin Kutepova <[email protected]>, Lockal <[email protected]>, Yuri Kozlov <[email protected]>, Баринов Владимир и Иван Павлов <[email protected]> Этот перевод является бесплатной документацией; прочитайте Стандартную общественную лицензию GNU версии 3 или более позднюю, чтобы узнать об условиях авторского права. Мы не несем НИКАКОЙ ОТВЕТСТВЕННОСТИ. Если вы обнаружите ошибки в переводе этой страницы руководства, пожалуйста, отправьте электронное письмо на [email protected]4 декабря 2022 г. | Linux man-pages 6.03 |