recvmsg(2) ソケットからメッセージを受け取る

Other Alias

recv, recvfrom

書式

#include <sys/types.h>
#include <sys/socket.h>


ssize_t recv(int sockfd, void *buf, size_t len, int flags);

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);

ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

説明

recv(), recvfrom(), recvmsg() コールは、 ソケットからメッセージを受け取るのに使用される。 これらはコネクションレス型のソケットにも接続指向 (connection-oriened) 型のソケットにも使用できる。 このページでは、まずこれら 3 つのシステムコールすべてに共通の機能について説明し、 システムコール間の違いについて説明する。

これらの三つのシステムコールはいずれも、成功した場合にはメッセージの長さを返す。 メッセージが長過ぎて指定されたバッファに入り切らなかった場合には、 メッセージを受信したソケットの種類によっては余分のバイトが捨てられる かもしれない。

ソケットに受け取るメッセージが存在しなかった場合、 受信用のコールはメッセージが到着するまで待つ。 ただし、ソケットが非停止 (nonblocking) に設定されていた場合 (fcntl(2) を参照) は -1 を返し、外部変数 errnoEAGAINEWOULDBLOCK を設定する。 これらの受信用のコールは、受信したデータのサイズが要求したサイズに 達するまで待つのではなく、何らかのデータを受信すると復帰する (受信されるデータの最大サイズは要求したサイズである)。

アプリケーションは select(2), poll(2), epoll(7) を使って、ソケットにさらにデータが到着しているかを判定することができる。

フラグ引き数

flags 引き数には、以下の値を 1つ以上、ビット単位の論理和 を取ったものを指定する:
MSG_CMSG_CLOEXEC (recvmsg() のみ; Linux 2.6.23)
(unix(7) で説明されている) SCM_RIGHTS 操作を使って UNIX ドメインのファイルディスクリプタ経由で受信した ファイルディスクリプタについて close-on-exec フラグをセットする。 このフラグは、 open(2) の O_CLOEXEC フラグと同じ理由で有用である。
MSG_DONTWAIT (Linux 2.2 以降)
非停止 (nonblocking) 操作を有効にする。 操作が停止するような場合にエラー EAGAINEWOULDBLOCK で呼び出しが失敗する (fcntl(2) の F_SETFLO_NONBLOCK フラグを指定することによっても有効にできる)。
MSG_ERRQUEUE (Linux 2.2 以降)
このフラグを指定すると、 キューに入れられたエラーをソケットのエラーキューから取りだせるようになる。 このエラーは補助メッセージに組み込まれて渡され、 この補助メッセージの種別はプロトコルに依存する (IPv4 の場合は IP_RECVERR)。 ユーザは十分なサイズのバッファを用意しなければならない。 補助メッセージに関するより詳細な情報は cmsg(3) および ip(7) を参照のこと。 エラーの原因となったオリジナルパケットのペイロードは、 msg_iovec 経由で通常のデータとして渡される。 エラーを起こしたデータグラムのオリジナルの宛先アドレスは、 msg_name 経由で参照できる。
ローカルなエラーの場合はアドレスは渡されない (これは cmsghdrcmsg_len メンバーでチェックできる)。 受信エラーの場合は MSG_ERRQUIEmsghdr にセットされる。 エラーが渡された後には、キューに入っている次のエラーに基いて、 処理待ちのソケット・エラーが再生成され、次のソケット操作の際に渡される。

このエラーは sock_extended_err 構造体で提供される:

#define SO_EE_ORIGIN_NONE    0
#define SO_EE_ORIGIN_LOCAL   1
#define SO_EE_ORIGIN_ICMP    2
#define SO_EE_ORIGIN_ICMP6   3
struct sock_extended_err
{
    uint32_t ee_errno;   /* error number */
    uint8_t  ee_origin;  /* where the error originated */
    uint8_t  ee_type;    /* type */
    uint8_t  ee_code;    /* code */
    uint8_t  ee_pad;     /* padding */
    uint32_t ee_info;    /* additional information */
    uint32_t ee_data;    /* other data */
    /* More data may follow */
};
struct sockaddr *SO_EE_OFFENDER(struct sock_extended_err *);
ee_errno にはキューに入れられたエラーの errno が入っている。 ee_origin にはエラーが発生した場所のオリジン・コード (origin code) が入っている。 他のフィールドはプロトコル依存である。 SO_EE_OFFENDER マクロは、この補助的なメッセージを引き数に取って、 エラーの発生したネットワークオブジェクトのアドレスへのポインタを返す。 アドレスが不明の場合には、 sockaddrsa_family メンバーが AF_UNSPEC になっている。 sockaddr の他のフィールドは不定である。 エラーの発生したパケットのペイロードは通常のデータとして渡される。
ローカルなエラーの場合はアドレスは渡されない (これは cmsghdrcmsg_len メンバーでチェックできる)。 受信エラーの場合は MSG_ERRQUIEmsghdr にセットされる。 エラーが渡された後には、キューに入っている次のエラーに基いて、 処理待ちのソケット・エラーが再生成され、次のソケット操作の際に渡される。
MSG_OOB
このフラグは、通常のデータ・ストリームでは受信できない 帯域外 (out-of-band) データの受信を要求する。 プロトコルによっては、 通常のデータ・キューの先頭に速達データを置くものがあるが、 そのようなプロトコルではこのフラグは使用できない。
MSG_PEEK
このフラグを指定すると、 受信キューの最初のデータを返すとき、キューからデータを削除しない。 したがって、この後でもう一度受信コールを呼び出すと、同じデータが返ることになる。
MSG_TRUNC (Linux 2.2 以降)
raw ソケット (AF_PACKET)、 Internet datagram ソケット (Linux 2.4.27/2.6.8 以降)、 netlink (Linux 2.6.22 以降) ソケット、 UNIX datagram ソケット (Linux 3.4 以降) の場合、パケットやデータグラムの長さが渡したバッファよりも長かった場合にも、 パケットやデータグラムの実際の長さを返す。

Internet ストリームソケットでの利用については tcp(7) を参照。

MSG_WAITALL (Linux 2.2 以降)
このフラグは、要求した量いっぱいのデータが到着するまで、 操作を停止 (block) するよう要求する。 但し、シグナルを受信したり、エラーや切断 (disconnect) が発生したり、 次に受信されるデータが異なる型だったりした場合には、 要求した量よりデータが少なくても返ることがある。

recvfrom()

recvfrom() は受信したメッセージをバッファ buf に格納する。 呼び出し元はバッファサイズを len で指定しなければならない。

src_addr が NULL 以外で、下層のプロトコルからメッセージの送信元アドレスが分かる場合、 この送信元アドレスが src_addr が指すバッファに格納される。 この場合、 addrlen は入出力両用の引き数となる。 呼び出し前に、呼び出し元は src_addr に割り当てたバッファの大きさで初期化しておくべきである。 返ってくる時には、 addrlen は送信元アドレスの実際の大きさに変更される。渡されたバッファが小さ過ぎる場合には、返されるアドレスの末尾は 切り詰められる。この場合には、 addrlen では、呼び出し時に渡された値よりも大きな値が返される。

呼び出し元が送信元アドレスを必要としない場合は、 src_addr には NULL を指定し、 addrlen には 0 を指定すべきである。

recv()

recv() コールは通常 接続済みの (connected) ソケットに対してのみ使用される (connect(2) 参照)。次の呼び出しと等価である。


    recvfrom(fd, buf, len, flags, NULL, 0));

recvmsg()

recvmsg() コールは、直接渡す引き数の数を減らすために msghdr 構造体を使用する。この構造体は <sys/socket.h> で以下のように定義されている:
struct iovec {                    /* Scatter/gather array items */
    void  *iov_base;              /* Starting address */
    size_t iov_len;               /* Number of bytes to transfer */
};
struct msghdr {
    void         *msg_name;       /* 追加のアドレス */
    socklen_t     msg_namelen;    /* アドレスのサイズ */
    struct iovec *msg_iov;        /* scatter/gather 配列 */
    size_t        msg_iovlen;     /* msg_iov の要素数 */
    void         *msg_control;    /* 補助データ (後述) */
    size_t        msg_controllen; /* 補助データバッファ長 */
    int           msg_flags;      /* 受信メッセージのフラグ */
};

msg_namemsg_namelen は、ソケットが接続されていない場合に送信元のアドレスを指定する。 名前が必要ない場合には msg_name にヌルポインタを指定する。 msg_iovmsg_iovlen フィールドは readv(2) に記述されているような分解/結合用のベクトル (scatter-gather locations) を指定する。 msg_control フィールドは msg_controllen の長さを持ち、他のプロトコル制御メッセージや 種々の補助データのためのバッファへのポインタである。 recvmsg() を呼ぶ際には、 msg_controllenmsg_control のバッファの長さを入れておく必要がある。 コールが成功して返った場合、制御メッセージ列の長さが入っている。

メッセージの形式は以下の通り:

struct cmsghdr {
    socklen_t     cmsg_len;     /* data byte count, including hdr */
    int           cmsg_level;   /* originating protocol */
    int           cmsg_type;    /* protocol-specific type */
/* followed by
    unsigned char cmsg_data[]; */
};

補助データは、 cmsg(3) に定義されたマクロ経由でのみアクセスすべきである。

例をあげると、 Linux はこの補助データのメカニズムを、 UNIX ドメインソケット上での拡張エラーや IP オプション、 ファイル・ディスクリプタの受け渡しに利用している。

msghdrmsg_flags フィールドは recvmsg() からのリターン時に設定される。ここにはいくつかのフラグが入る。

MSG_EOR
これはレコードの終り (end-of-record) を示し、 返されたデータが完全なレコードであることを示す (一般的には SOCK_SEQPACKET 型のソケットで使用される)。
MSG_TRUNC
データグラムが与えられたバッファより大きかったために、 データグラムのはみ出した部分が捨てられたことを示す。
MSG_CTRUNC
補助データのためのバッファが不足したために、 制御データの一部が捨てられたことを示す。
MSG_OOB
速達データや帯域外データを受信したことを示す。
MSG_ERRQUEUE
データは受信しなかったが ソケットのエラー・キューから拡張エラーを受信したことを示す。

返り値

これらのコールは受信したバイト数を返す。 エラーの場合は -1 を返し、 errno にエラーを示す値を設定する。

ストリームソケットの接続相手が正しくシャットダウンを実行した場合は、 返り値は 0 (昔ながらの "end-of-file" の戻り値) となる。

いくつかのドメインのデータグラムソケット (UNIX ドメインやインターネットドメインなど) では、長さ 0 のデータグラムが送信できる。 このようなデータグラムを受信した場合、 返り値は 0 となる。

ストリームソケットに対する受信要求バイト数が 0 だった場合も、 値 0 が返される。

エラー

これらはソケット層で発生する一般的なエラーである。 他のエラーが下層のプロトコル・モジュールで生成され、 返されるかもしれない。 それらのマニュアルを参照すること。
EAGAIN または EWOULDBLOCK
ソケットが非停止 (nonblocking) に設定されていて 受信操作が停止するような状況になったか、 受信に時間切れ (timeout) が設定されていて データを受信する前に時間切れになった。 POSIX.1-2001 は、この場合にどちらのエラーを返すことも認めており、 これら 2 つの定数が同じ値を持つことも求めていない。 したがって、移植性が必要なアプリケーションでは、両方の可能性を 確認すべきである。
EBADF
引き数 sockfd が不正なディスクリプタである。
ECONNREFUSED
リモートのホストでネットワーク接続が拒否された (よくある理由としては、要求したサービスが起動されていないなどがある)。
EFAULT
受信バッファへのポインタがプロセスのアドレス空間外を指している。
EINTR
データを受信する前に、シグナルが配送されて割り込まれた。 signal(7) 参照。
EINVAL
不正な引き数が渡された。
ENOMEM
recvmsg() のためのメモリが確保できなかった。
ENOTCONN
ソケットに接続指向プロトコルが割り当てられており、 まだ接続されていない (connect(2) と accept(2) を参照のこと)。
ENOTSOCK
引き数 sockfd がソケットを参照していない。

準拠

4.4BSD (これらの関数は 4.2BSD で現われた), POSIX.1-2001。

POSIX.1-2001 では、 MSG_OOB, MSG_PEEK, MSG_WAITALL フラグだけが記載されている。

注意

上記のプロトタイプは glibc2 にしたがっている。 Single UNIX Specification でも同様だが、 返り値の型が ssize_t となっている (一方で 4.x BSD や libc4 や libc5 は全て int を使用している)。 flags 引き数は 4.x BSD では int だが、libc4 と libc5 では unsigned int である。 len 引き数は 4.x BSD では int だが、 libc4 と libc5 では size_t である。 addrlen 引き数は 4.x BSD, libc4, libc5 では int * である。 現在の socklen_t * は POSIX で発案された。 accept(2) も参照すること。

POSIX.1-2001 では、構造体 msghdr のフィールド msg_controllensocklen_t 型であるべきだとされているが、 現在の glibc では size_t 型である。

recvmmsg(2) には、一度の呼び出しでの複数のデータグラムに使用できる Linux 固有の システムコールに関する情報が書かれている。

recvfrom() の利用例が getaddrinfo(3) に記載されている。

この文書について

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