RECVMMSG - Linux手册页

时间:2019-08-20 17:59:14  来源:igfitidea点击:

Linux程序员手册 第2部分
更新日期: 2020-06-09

名称

recvmmsg-在套接字上接收多个消息

语法

#define _GNU_SOURCE         /* See 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结构定义为:

struct mmsghdr {
    struct msghdr msg_hdr;  /* Message header */
    unsigned int  msg_len;  /* Number of received bytes for header */
};

msg_hdr字段是msghdr结构,如recvmsg(2)中所述。 msg_len字段是为条目中的消息返回的字节数。该字段的值与标头上单个recvmsg(2)的返回值相同。

flags参数包含在一起进行或运算的标志。这些标志与为recvmsg(2)记录的标志相同,并增加了以下内容:

MSG_WAITFORONE(since Linux 2.6.34)
收到第一条消息后,打开MSG_DONTWAIT。

timeout参数指向为接收操作定义超时(秒加纳秒)的结构timespec(请参阅clock_gettime(2))(但请参阅BUGS!)。 (此间隔将四舍五入为系统时钟的粒度,并且内核调度延迟意味着阻塞间隔可能会少量溢出。)如果超时为NULL,则操作将无限期阻塞。

阻塞的recvmmsg()调用会阻塞,直到收到vlen消息或超时到期为止。无阻塞呼叫将读取尽可能多的消息(达到vlen指定的限制)并立即返回。

recvmmsg()返回时,msgvec的连续元素将更新为包含有关每个接收到的消息的信息:msg_len包含接收到的消息的大小; msg_hdr的子字段按照recvmsg(2)中的描述进行更新。调用的返回值指示已更新的msgvec元素的数量。

返回值

成功时,recvmmsg()返回msgvec中收到的消息数;如果出错,则返回-1,并且将errno设置为指示错误。

错误说明

错误与recvmsg(2)相同。此外,可能会发生以下错误:

EINVAL
超时无效。

另请参阅错误。

版本

在Linux 2.6.33中添加了recvmmsg()系统调用。在glibc中的支持已在2.12版中添加。

遵循规范

recvmmsg()是特定于Linux的。

BUGS

超时参数不能按预期工作。仅在收到每个数据报之后才检查超时,因此,如果在超时到期之前最多接收到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 messages received
1 11782
2 11345
3 304
4 13514
5 28421

Program source

#define _GNU_SOURCE
#include <netinet/ip.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>

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

    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 (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 (i = 0; i < retval; i++) {
        bufs[i][msgs[i].msg_len] = 0;
        printf("%d %s", i+1, bufs[i]);
    }
    exit(EXIT_SUCCESS);
}

另外参见

clock_gettime(2),recvmsg(2),sendmmsg(2),sendmsg(2),socket(2),socket(7)

出版信息

这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/