Provided by: manpages-ja-dev_0.5.0.0.20180315+dfsg-1_all bug

名前

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

書式

       #define _GNU_SOURCE         /* feature_test_macros(7) 参照 */
       #include <sys/socket.h>

       int recvmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen,
                    unsigned 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 が無効である。

バージョン

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

準拠

       recvmmsg() は Linux 固有である。

       以下のプログラムは、 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, i;
           struct sockaddr_in sa;
           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);
           }

           sa.sin_family = AF_INET;
           sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
           sa.sin_port = htons(1234);
           if (bind(sockfd, (struct sockaddr *) &sa, sizeof(sa)) == -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);
       }

バグ

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

関連項目

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

この文書について

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