名 前
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/ に 書 か れ て い る 。