SENDMMSG(2)

名前
sendmmsg - 複数のメッセージをソケットへ送信する

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

int sendmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen,
             int flags);

説明
sendmmsg() システムコールは sendmsg(2) の拡張で、 このシステムコールを使うと一度の呼び出しでソケットに複数のメッセージを送信できる (アプリケーションによっては性能上のメリットがある)。

sockfd 引数は、 データを送信するソケットのファイルディスクリプターである。

msgvec 引数は mmsghdr 構造体の配列である。 この配列の大きさは vlen で指定する。

mmsghdr 構造体は <sys/socket.h> で次のように定義されている。

    struct mmsghdr {
        struct msghdr msg_hdr;  /* メッセージヘッダー */
        unsigned int  msg_len;  /* 送信されたバイト数 */
    };

msg_hdr フィールドは、 sendmsg(2) で説明されている msghdr 構造体である。 msg_len フィールドは msg_hdr から送信されたメッセージのバイト数を返すのに使用される。 この値は sendmsg(2) をこのヘッダーに対して呼び出した場合の返り値と同じである。

flags 引数には複数のフラグを論理和 (OR) で指定できる。フラグは sendmsg(2) と同じである。

停止 (blocking) モードの sendmmsg() の呼び出しは、 vlen 個のメッセージが送信されるまで停止する。 非停止 (nonblocking) モードの呼び出しでは、 送信できるだけのメッセージ (最大で vlen 個) を送信し、 すぐに返る。

sendmmsg() が返った際には、 msgvec の送信が行われた要素の msg_len フィールドは、対応する msg_hdr から送信されたバイト数が入っている。 呼び出しの返り値は、更新された msgvec の要素数である。

返り値
成功すると、 sendmmsg() は msgvec から送信されたメッセージ数を返す。 返り値が vlen よりも小さい場合、 呼び出した側では再度 sendmmsg を呼び出して残りのメッセージを送信することができる。

エラーの場合、 -1 を返し、 errno にエラーを示す値を設定する。

エラー
エラーは sendmsg(2) と同じである。 エラーが返されるのは、 データグラムが全く送信できなかった場合のみである。「バグ」も参照のこと。

バージョン
sendmmsg() システムコールは Linux 3.0 で追加された。 glibc でのサポートはバージョン 2.14 で追加された。

準拠
sendmmsg() は Linux 固有である。

注意
vlen に指定できる値の最大値は UIO_MAXIOV (1024) である。

バグ
If an error occurs after at least one message has been sent, the call succeeds, and returns the number of messages sent. The error code is lost. The caller can retry the transmission, starting at the first failed message, but there is no guarantee that, if an error is returned, it will be the same as the one that was lost on the previous call.

例
以下の例では、 sendmmsg() を使って、 一度のシステムコールで、 onetwo と three を二つの別々の UDP データグラムで送信する。 一つ目のデータグラムの内容は、二つのバッファーから取得される。

    #define _GNU_SOURCE
    #include <netinet/ip.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    int
    main(void)
    {
        int sockfd;
        struct sockaddr_in addr;
        struct mmsghdr msg[2];
        struct iovec msg1[2], msg2;
        int retval;
        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 (connect(sockfd, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
            perror("connect()");
            exit(EXIT_FAILURE);
        }
        memset(msg1, 0, sizeof(msg1));
        msg1[0].iov_base = "one";
        msg1[0].iov_len = 3;
        msg1[1].iov_base = "two";
        msg1[1].iov_len = 3;
        memset(&msg2, 0, sizeof(msg2));
        msg2.iov_base = "three";
        msg2.iov_len = 5;
        memset(msg, 0, sizeof(msg));
        msg[0].msg_hdr.msg_iov = msg1;
        msg[0].msg_hdr.msg_iovlen = 2;
        msg[1].msg_hdr.msg_iov = &msg2;
        msg[1].msg_hdr.msg_iovlen = 1;
        retval = sendmmsg(sockfd, msg, 2, 0);
        if (retval == -1)
            perror("sendmmsg()");
        else
            printf("%d messages sent\n", retval);
        exit(0);
    }

関連項目
recvmmsg(2), sendmsg(2), socket(2), socket(7)

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