RECVMMSG

Section: Linux Programmer's Manual (2)
Updated: 2020-11-01
Index JM Home Page
 

名前

recvmmsg - 複数のメッセージをソケットから受信する  

書式

#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 フィールドは、 recvmsg(2) で説明されている msghdr 構造体である。 msg_len フィールドは、 このエントリーで返されるメッセージのバイト数で、 このヘッダーに対して recvmsg(2) を呼び出した場合の返り値と同じ値が入る。

flags 引数には複数のフラグを論理和 (OR) で指定できる。 フラグは、 recvmsg(2) で説明されているものに加えて、以下が使用できる。

MSG_WAITFORONE (Linux 2.6.34 以降)
最初のメッセージを受信後に MSG_DONTWAIT を有効にする。

timeout 引数は struct timespec (clock_gettime(2) 参照) へのポインターで、 この構造体で受信操作のタイムアウト (秒とナノ秒) を指定する (ただし、バグを参照のこと) (待ち時間はシステムクロックの粒度に切り上げられ、カーネルのスケジューリング遅延により少しだけ長くなる可能性がある)。 timeoutが NULL の場合、 受信操作は無期限に停止 (block) する。

停止 (blocking) モードの recvmmsg() の呼び出しは、 vlen 個のメッセージを受信するか、タイムアウトが満了するまで停止する。 非停止 (nonblocking) モードの呼び出しでは、 読み出し可能なメッセージ (最大で vlen 個) を読み出し、 すぐに返る。

recvmmsg() が返った際には、 msgvec のうちデータが受信された要素には、受信したそれぞれのメッセージの情報が格納されている。 また、 msg_len には受信したメッセージの大きさが入り、 msg_hdr の各フィールドは recvmsg(2) に書かれている通りに更新される。 呼び出しの返り値は、更新された msgvec の要素数である。  

返り値

成功すると、 recvmmsg() は msgvec に受信されたメッセージ数を返す。 エラーの場合、 -1 を返し、 errno にエラーを示す値を設定する。  

エラー

エラーは recvmsg(2) と同じである。 これに加えて、以下のエラーが起こる場合がある。
EINVAL
timeout が無効である。

See also BUGS.  

バージョン

recvmmsg() システムコールは Linux 2.6.33 で追加された。 glibc でのサポートはバージョン 2.12 以降で利用可能である。  

準拠

recvmmsg() は Linux 固有である。  

バグ

timeout 引数は意図した通りには動作しない。 タイムアウトは各データグラムの受信後にのみチェックされる。 そのため、 タイムアウトが満了する前に vlen-1 個のデータグラムを受信し、 その後全くデータグラムを受信しなかった場合、 呼び出しはずっと停止し続けてしまう。

If an error occurs after at least one message has been received, the call succeeds, and returns the number of messages received. The error code is expected to be returned on a subsequent call to recvmmsg(). In the current implementation, however, the error code can be overwritten in the meantime by an unrelated network event on a socket, for example an incoming ICMP packet.  

以下のプログラムは、 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  

プログラムのソース

#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;
    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 (int 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 (int 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)  

この文書について

この man ページは Linux man-pages プロジェクトのリリース 5.10 の一部である。プロジェクトの説明とバグ報告に関する情報は https://www.kernel.org/doc/man-pages/ に書かれている。


関連キーワード

受信, recvmmsg, メッセージ, struct, timeout, int, addr, recvmsg, msgs, sockfd 

Index

名前
書式
説明
返り値
エラー
バージョン
準拠
バグ
プログラムのソース
関連項目
この文書について

This document was created by man2html, using the manual pages.
Time: 03:54:17 GMT, May 19, 2022