Provided by: manpages-ja-dev_0.5.0.0.20221215+dfsg-1_all
名前
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/ に書かれている。