RECV(2)

名称
recv, recvfrom, recvmsg - ソケットからメッセージを受信する

ライブラリ
libc

書式
<sys/types.h> <sys/socket.h> ssize_t recv(int s, void *buf, size_t len, int flags) ssize_t recvfrom(int s, void * restrict buf, size_t len, int flags, struct sockaddr * restrict from, socklen_t * restrict fromlen) ssize_t recvmsg(int s, struct msghdr *msg, int flags)

解説
recvfrom() と recvmsg() システムコールは、ソケットからのメッセージを受信するのに使用されます。 ソケットが接続指向であるかどうかにかかわらず、ソケット上のデータを 受信するのに使用できます。

from が nil でなく、ソケットが接続指向でない場合、 ここにはメッセージのソースアドレスが保存されます。 fromlen 引数は値と結果の引数であり、 from に対応するバッファのサイズに初期化され、 戻り時には保存されたアドレスの実際のサイズを示すように変更されます。

recv() システムコールは、通常 接続された ソケット上だけで使用され (connect(2) を参照)、 from 引数に nil を指定した recvfrom() と同一です。 これは冗長なので、将来のリリースではサポートされない可能性があります。

これら 3 つのルーチンは正常に完了するとメッセージの長さを返します。 メッセージが長すぎて指定のバッファに収まらない場合、 メッセージを受信したソケットのタイプによっては 超過分のバイトが破棄されることがあります (socket(2) を参照)。

ソケットにメッセージが無い場合は、ソケットが非ブロッキング (fcntl(2) を参照) の場合を除き、呼び出しはメッセージが到着するのを待ちます。 ソケットが非ブロッキングの場合、値 -1 が返され、外部変数 errno が EAGAIN に設定されます。 通常、受信呼び出しは要求された量を受信するまで待たずに、 要求された量を上限として得られたデータを返します。 この動作は、 getsockopt(2) で解説されているソケットレベルのオプション SO_RCVLOWAT および SO_RCVTIMEO によって影響を受けます。

次のデータがいつ到着するかを判定するには select(2) システムコールを使うことができます。

recv 関数への flags 引数は、次の値の 1 つまたは複数の論理和 (or) から成ります:
MSG_OOB | プロセス帯域外データ
MSG_PEEK | 着信メッセージの覗き見 (peek)
MSG_WAITALL | 要求の完全な実行、またはエラーを待つ
MSG_DONTWAIT | ブロックしない

MSG_OOB フラグは帯域外データの受信を要求し、 通常のデータストリームからは受信しません。 急送データを通常のデータ待ち行列の先頭に配置するプロトコルもありますが、 このフラグはそのようなプロトコルでは使用できません。 MSG_PEEK フラグは受信待ち行列の先頭からデータを除去することなく、 そのデータを返します。 したがって、後続の受信呼び出しは同じデータを返します。 MSG_WAITALL フラグは要求が完全に満たされるまでブロックするように要求します。 しかし、シグナルが捕捉された場合、エラーまたは切断が発生した場合、 または受信する次のデータが返されたタイプと異なる 場合、呼び出しは要求されたより少ないデータを返す可能性があります。 MSG_DONTWAIT フラグは、フラグが指定されてなかったらブロックするような時に、 戻ることを要求します。 利用可能なデータが無い場合には、 errno が EAGAIN に設定されます。 このフラグは、厳格な ANSI または C99 のコンパイルモードでは利用できません。

recvmsg() システムコールは、直接に指定される引数の数を最小にするために msghdr 構造体を使用します。 この構造体は <sys/socket.h> で定義されているように、次の形式になっています:

    struct msghdr {
    	caddr_t	msg_name;	/* アドレス(オプション) */
    	u_int	msg_namelen;	/* アドレスのサイズ */
    	struct	iovec *msg_iov;	/* スキャッタ / ギャザー配列 */
    	u_int	msg_iovlen;	/* msg_iov の要素数 */
    	caddr_t	msg_control;	/* 補助データ、後述 */
    	u_int	msg_controllen; /* 補助データのバッファ長 */
    	int	msg_flags;	/* 受信されたメッセージ上のフラグ */
    };

ここで msg_name と msg_namelen は、ソケットが接続されていない場合に、宛先アドレスを指定します。 名前を要求しない場合や必要でない場合、 msg_name は NULL ポインタとして指定できます。 msg_iov と msg_iovlen 引数は read(2) で説明されているようにスキャッタ / ギャザーの場所を記述します。 msg_control 引数は、長さが msg_controllen の、他のプロトコル制御に関連するメッセージまたはその他の 各種補助データ用のバッファを指しています。 メッセージは次の形式です:

    struct cmsghdr {
    	u_int	cmsg_len;	/* データバイトカウント、hdr を含む */
    	int	cmsg_level;	/* メッセージを生成したプロトコル */
    	int	cmsg_type;	/* プロトコルに固有のタイプ */
    /*	u_char	cmsg_data[]; が後に続く */
    };

たとえば、これを使用して XNS/SPP において データストリームの変化を知ることができます。 また、ISO において accept() システムコールの直後に、データバッファを伴わずに recvmsg を要求して、 ユーザ接続要求データを得ることができるでしょう。

オープンファイル記述子はこれで AF_UNIX ドメインソケット用の補助データとして引き渡され、その際、 cmsg_level が SOL_SOCKET に設定され、 cmsg_type が SCM_RIGHTS に設定されます。

SCM_CREDS の cmsg_type を使用して、プロセスの認証情報を AF_UNIX ドメインソケット用の補助データとして 渡すこともできます。 このケースでは、 cmsg_data は、構造体 cmsgcred である必要があります。 これは次のように <sys/socket.h> 内で定義されています:

    struct cmsgcred {
    	pid_t	cmcred_pid;		/* 送信プロセスの PID */
    	uid_t	cmcred_uid;		/* 送信プロセスの実 UID */
    	uid_t	cmcred_euid;		/* 送信プロセスの実効 UID */
    	gid_t	cmcred_gid;		/* 送信プロセスの実 GID */
    	short	cmcred_ngroups;		/* グループの数 */
    	gid_t	cmcred_groups[CMGROUP_MAX];	/* グループ */
    };

カーネルは送信プロセスの認証情報を記入し、それを受信側へ配信します。

msg_flags フィールドは受信済みメッセージに従って戻り時に設定されます。 MSG_EOR は end-of-record、つまり返されたデータでレコードが 完結していることを示します (一般には、タイプ SOCK_SEQPACKET のソケットとともに使用されます)。 MSG_TRUNC は、提供されたバッファよりデータグラムが大きかったので、 データグラムの後ろの部分が切り捨てられたことを示します。 MSG_CTRUNC は、補助データ用のバッファ内の空間の不足のためにいくらかの制御データが 切り捨てられたことを示します。 MSG_OOB は、急送または帯域外データが受信されたことを示します。

戻り値
これらの呼び出しは受信したバイト数を返し、エラーが起きた場合は -1 を返します。

エラー
呼び出しは次の場合に失敗します:

[EBADF]
    引数 s が有効な記述子ではありません。

[ENOTCONN]
    ソケットは接続指向プロトコルと結び付けられていますが、接続されていません (connect(2) と accept(2) を参照)。

[ENOTSOCK]
    引数 s はソケットを参照していません。

[EAGAIN]
    ソケットが非ブロッキングとマークされているとき、 受信操作でブロックしました。 あるいは、受信タイムアウトが設定されていて、 データが受信される前にタイムアウトになりました。

[EINTR]
    データが受信可能になる前に、受信がシグナルによって割込まれました。

[EFAULT]
    受信バッファポインタが、プロセスに割り当てられたアドレス空間の 範囲外を指しています。

関連項目
fcntl(2), getsockopt(2), read(2), select(2), socket(2)

歴史
recv() 関数は 4.2BSD で登場しました。