LPFN_WSARECVMSG
コールバックシグネチャ
INT LPFN_WSARECVMSG(
SOCKET s,
WSAMSG* lpMsg,
DWORD* lpdwNumberOfBytesRecvd,
OVERLAPPED* lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);パラメーター
| フィールド | 型 | 説明 |
|---|---|---|
| s | SOCKET | ソケットを識別する記述子です。 |
| lpMsg | WSAMSG* | msghdr 構造体に関する Posix.1g 仕様に基づく WSAMSG 構造体へのポインターです。 |
| lpdwNumberOfBytesRecvd | DWORD* | WSARecvMsg の操作が即座に完了した場合に、この呼び出しで受信したバイト数を格納する DWORD へのポインターです。 誤った結果を招かないように、lpOverlapped パラメーターが NULL でない場合は、このパラメーターに NULL を渡してください。このパラメーターを NULL にできるのは、lpOverlapped パラメーターが NULL でない場合のみです。 |
| lpOverlapped | OVERLAPPED* | WSAOVERLAPPED 構造体へのポインターです。非オーバーラップの構造体では無視されます。 |
| lpCompletionRoutine | LPWSAOVERLAPPED_COMPLETION_ROUTINE | 受信操作の完了時に呼び出される完了ルーチンへのポインターです。非オーバーラップの構造体では無視されます。 |
公式ドキュメント
LPFN_WSARECVMSG は関数ポインター型です。アプリ側で、これに一致する WSARecvMsg コールバック関数を実装します。システムは、接続済みソケットを介してメモリ上のデータまたはファイルデータを転送するために、このコールバック関数を使用します。
WSARecvMsg コールバック関数は、接続済みおよび未接続のソケットから、メッセージとともに補助データ (制御情報) を受信します。
この関数は、Windows Sockets 仕様に対する Microsoft 固有の拡張です。
戻り値
エラーが発生せず、受信操作が即座に完了した場合、WSARecvMsg はゼロを返します。この場合、呼び出し元のスレッドがアラート可能状態になった時点で完了ルーチンが呼び出されるよう、既にスケジュールされています。それ以外の場合は SOCKET_ERROR が返され、WSAGetLastError を呼び出すことで具体的なエラーコードを取得できます。エラーコード WSA_IO_PENDING は、オーバーラップ操作が正常に開始され、完了が後で通知されることを示します。
これ以外のエラーコードは、操作が正常に開始されなかったことを示し、オーバーラップ操作を要求していた場合でも完了通知は発生しません。
| エラーコード | 意味 |
|---|---|
| WSAECONNRESET | UDP データグラムソケットの場合、このエラーは、直前の送信操作によって ICMP の "Port Unreachable" メッセージが返されたことを示します。 |
| WSAEFAULT | lpBuffers、lpFlags、lpFrom、lpNumberOfBytesRecvd、lpFromlen、lpOverlapped、lpCompletionRoutine のいずれかのパラメーターが、ユーザーアドレス空間の有効な部分に完全には収まっていません。つまり、lpFrom バッファーが小さすぎて、相手のアドレスを格納できませんでした。このエラーは、lpMsg パラメーターが指す WSAMSG 構造体の name メンバーが NULL ポインターであり、かつ WSAMSG 構造体の namelen メンバーがゼロに設定されていない場合にも返されます。さらに、lpMsg パラメーターが指す WSAMSG 構造体の Control.buf メンバーが NULL ポインターであり、かつ WSAMSG 構造体の Control.len メンバーがゼロに設定されていない場合にも返されます。 |
| WSAEINPROGRESS | ブロッキングの Windows Sockets 1.1 呼び出しが進行中であるか、サービスプロバイダーがコールバック関数をまだ処理中です。 |
| WSAEINTR | ブロッキングの Windows Socket 1.1 呼び出しが WSACancelBlockingCall によって取り消されました。 |
| WSAEINVAL | ソケットがバインドされていません (たとえば bind によるバインドが行われていません)。 |
| WSAEMSGSIZE | メッセージが大きすぎて指定されたバッファーに収まりませんでした。また (信頼性のないプロトコルの場合のみ)、バッファーに収まらなかったメッセージの末尾部分は破棄されました。 |
| WSAENETDOWN | ネットワークサブシステムで障害が発生しました。 |
| WSAENETRESET | データグラムソケットの場合、このエラーは TTL (time to live) が期限切れになったことを示します。 |
| WSAENOTCONN | ソケットが接続されていません (コネクション指向のソケットのみ)。 |
| WSAETIMEDOUT | ソケットがタイムアウトしました。このエラーは、SO_RCVTIMEO ソケットオプションで待機のタイムアウトが指定されており、そのタイムアウトを超過した場合に返されます。 |
| WSAEOPNOTSUPP | このソケット操作はサポートされていません。このエラーは、lpMsg パラメーターが指す WSAMSG 構造体の dwFlags メンバーに、データグラム以外のソケットに対して MSG_PEEK 制御フラグが含まれている場合に返されます。 |
| WSAEWOULDBLOCK | Windows NT: オーバーラップソケットの場合: 未処理のオーバーラップ I/O 要求が多すぎます。非オーバーラップソケットの場合: ソケットが非ブロッキングとしてマークされており、受信操作を即座に完了できません。 |
| WSANOTINITIALISED | この関数を使用する前に、WSAStartup の呼び出しが成功している必要があります。 |
| WSA_IO_PENDING | オーバーラップ操作が正常に開始され、完了は後で通知されます。 |
| WSA_OPERATION_ABORTED | ソケットが閉じられたため、オーバーラップ操作は取り消されました。 |
解説(Remarks)
WSARecvMsg 関数は、接続済みおよび未接続のソケットからデータと省略可能な制御情報を受信するために、WSARecv 関数および WSARecvFrom 関数の代わりに使用できます。WSARecvMsg 関数は、データグラムソケットおよび raw ソケットでのみ使用できます。s パラメーターのソケット記述子は、ソケットの種類に SOCK_DGRAM または SOCK_RAW を設定して開いておく必要があります。
Note WSARecvMsg 関数の関数ポインターは、実行時に SIO_GET_EXTENSION_FUNCTION_POINTER オペコードを指定して WSAIoctl 関数を呼び出して取得する必要があります。WSAIoctl 関数に渡す入力バッファーには、WSARecvMsg 拡張関数を識別する値を持つグローバル一意識別子 (GUID) である WSAID_WSARECVMSG を格納する必要があります。成功すると、WSAIoctl 関数が返す出力に WSARecvMsg 関数へのポインターが格納されます。WSAID_WSARECVMSG GUID は Mswsock.h ヘッダーファイルで定義されています。
lpMsg パラメーターが指す WSAMSG 構造体の dwFlags メンバーには、入力時に MSG_PEEK 制御フラグのみを指定できます。
オーバーラップソケットは、WSA_FLAG_OVERLAPPED フラグを設定して WSASocket 関数を呼び出すことで作成されます。オーバーラップソケットでは、lpOverlapped と lpCompletionRoutine の両方のパラメーターが NULL でない限り、情報の受信にオーバーラップ I/O が使用されます。lpOverlapped と lpCompletionRoutine の両方のパラメーターが NULL の場合、そのソケットは非オーバーラップソケットとして扱われます。
オーバーラップソケットでは完了通知が発生します。バッファーがトランスポートによって消費されると、完了ルーチンがトリガーされるか、イベントオブジェクトがシグナル状態に設定されます。操作が即座に完了しない場合、最終的な完了状態は完了ルーチンを通じて、または WSAGetOverlappedResult 関数を呼び出して取得します。
オーバーラップソケットでは、WSARecvMsg を使用して 1 つ以上のバッファーをポストします。受信データは利用可能になり次第これらのバッファーに格納され、その後、アプリケーションが指定した完了通知 (完了ルーチンの呼び出し、またはイベントオブジェクトのシグナル設定) が発生します。操作が即座に完了しない場合、最終的な完了状態は完了ルーチンまたは WSAGetOverlappedResult 関数を通じて取得します。
非オーバーラップソケットの場合、ブロッキングのセマンティクスは標準の recv 関数と同一であり、lpOverlapped および lpCompletionRoutine パラメーターは無視されます。トランスポートが既に受信してバッファリングしているデータは、指定されたユーザーバッファーにコピーされます。ブロッキングソケットで、トランスポートが受信してバッファリングしたデータがまだ存在しない場合、呼び出しはデータを受信するまでブロックします。Windows Sockets 2 では、この関数に対する標準的なブロッキングのタイムアウト機構は定義されていません。バイトストリームとして動作するプロトコルの場合、スタックは利用可能なバッファー領域と受信済みデータの量の範囲内で、可能な限り多くのデータを返そうとします。ただし、1 バイトでも受信すれば呼び出し元のブロックは解除されます。2 バイト以上が返される保証はありません。メッセージ指向として動作するプロトコルの場合、呼び出し元のブロックを解除するには完全なメッセージが必要です。
Note SO_RCVTIMEO ソケットオプションは、ブロッキングソケットにのみ適用されます。
バッファーは、lpMsg パラメーターが指す WSAMSG 構造体の lpBuffers メンバーが指す配列内の順序どおりに埋められ、隙間ができないように詰めて格納されます。
この関数がオーバーラップ方式で完了する場合、この呼び出しから戻る前にこの WSABUF 構造体を取り込むのは、Winsock サービスプロバイダーの責任です。これにより、アプリケーションは、lpMsg パラメーターが指す WSAMSG 構造体の lpBuffers メンバーが指す WSABUF 配列をスタック上に構築できます。
メッセージ指向のソケット (ソケットの種類が SOCK_DGRAM または SOCK_RAW) の場合、受信メッセージはバッファーの合計サイズまでバッファーに格納され、オーバーラップソケットでは完了通知が発生します。メッセージがバッファーより大きい場合、バッファーにはメッセージの先頭部分が格納されて超過分のデータは失われ、WSARecvMsg はエラー WSAEMSGSIZE を生成します。
SOCK_DGRAM 型または SOCK_RAW 型の IPv4 ソケットで IP_PKTINFO ソケットオプションが有効になっている場合、WSARecvMsg 関数は、lpMsg パラメーターが指す WSAMSG 構造体にパケット情報を返します。返される WSAMSG 構造体の制御データオブジェクトの 1 つには、受信したパケットのアドレス情報を格納するための in_pktinfo 構造体が含まれます。
IPv4 経由で受信したデータグラムの場合、受信した WSAMSG 構造体の Control メンバーには、WSACMSGHDR 構造体を含む WSABUF 構造体が格納されます。この WSACMSGHDR 構造体の cmsg_level メンバーには IPPROTO_IP、cmsg_type メンバーには IP_PKTINFO、cmsg_data メンバーには、受信した IPv4 パケットのアドレス情報を格納するための in_pktinfo 構造体が格納されます。in_pktinfo 構造体内の IPv4 アドレスは、そのパケットを受信した IPv4 アドレスです。
SOCK_DGRAM 型または SOCK_RAW 型の IPv6 ソケットで IPV6_PKTINFO ソケットオプションが有効になっている場合、WSARecvMsg 関数は、lpMsg パラメーターが指す WSAMSG 構造体にパケット情報を返します。返される WSAMSG 構造体の制御データオブジェクトの 1 つには、受信したパケットのアドレス情報を格納するための in6_pktinfo 構造体が含まれます。
IPv6 経由で受信したデータグラムの場合、受信した WSAMSG 構造体の Control メンバーには、WSACMSGHDR 構造体を含む WSABUF 構造体が格納されます。この WSACMSGHDR 構造体の cmsg_level メンバーには IPPROTO_IPV6、cmsg_type メンバーには IPV6_PKTINFO、cmsg_data メンバーには、受信した IPv6 パケットのアドレス情報を格納するための in6_pktinfo 構造体が格納されます。in6_pktinfo 構造体内の IPv6 アドレスは、そのパケットを受信した IPv6 アドレスです。
デュアルスタックのデータグラムソケットで、IPv4 経由で受信したデータグラムについて WSARecvMsg 関数に WSAMSG 構造体でパケット情報を返させる必要がある場合は、そのソケットで IP_PKTINFO ソケットオプションを true に設定する必要があります。ソケットで IPV6_PKTINFO オプションのみを true に設定した場合、IPv6 経由で受信したデータグラムにはパケット情報が提供されますが、IPv4 経由で受信したデータグラムには提供されないことがあります。
Ws2ipdef.h ヘッダーファイルは Ws2tcpip.h に自動的にインクルードされるため、直接使用しないでください。
Note 特定のスレッドが開始したすべての I/O は、そのスレッドの終了時に取り消されます。オーバーラップソケットでは、操作が完了する前にスレッドが閉じられると、保留中の非同期操作が失敗することがあります。詳細については、ExitThread を参照してください。
Windows Phone 8: この関数は、Windows Phone 8 以降の Windows Phone ストアアプリでサポートされます。
Windows 8.1 および Windows Server 2012 R2: この関数は、Windows 8.1、Windows Server 2012 R2 以降の Windows ストアアプリでサポートされます。
dwFlags
入力時、lpMsg パラメーターが指す WSAMSG 構造体の dwFlags メンバーを使用すると、対象のソケットに指定されたソケットオプションに加えて、関数呼び出しの動作に影響を与えることができます。つまり、この関数のセマンティクスは、ソケットオプションと WSAMSG 構造体の dwFlags メンバーによって決まります。lpMsg パラメーターが指す WSAMSG 構造体の dwFlags メンバーに入力値として指定できるのは、MSG_PEEK のみです。
| 値 | 意味 |
|---|---|
| MSG_PEEK | 受信データを覗き見します。データはバッファーにコピーされますが、入力キューからは削除されません。このフラグは非オーバーラップソケットでのみ有効です。 |
入力時に dwFlags メンバーへ指定できる値は、Winsock2.h ヘッダーファイルで定義されています。
出力時、lpMsg パラメーターが指す WSAMSG 構造体の dwFlags メンバーには、次の値の組み合わせが返されることがあります。
| 値 | 意味 |
|---|---|
| MSG_BCAST | データグラムが、リンク層のブロードキャストとして、またはブロードキャストアドレスである宛先 IP アドレス宛てに受信されました。 |
| MSG_CTRUNC | 制御 (補助) データが切り詰められました。プロセスが確保した領域よりも多くの制御データが存在しました。 |
| MSG_MCAST | データグラムが、マルチキャストアドレスである宛先 IP アドレス宛てに受信されました。 |
| MSG_TRUNC | データグラムが切り詰められました。プロセスが確保した領域よりも多くのデータが存在しました。 |
Windows Vista 以降向けにリリースされた Microsoft Windows Software Development Kit (SDK) では、ヘッダーファイルの構成が変更されており、出力時の dwFlags メンバーに指定できる値は Ws2def.h ヘッダーファイルで定義されています。このヘッダーファイルは Winsock2.h ヘッダーファイルによって自動的にインクルードされます。
Windows Server 2003 以前のバージョンの Platform Software Development Kit (SDK) では、出力時の dwFlags メンバーに指定できる値は Mswsock.h ヘッダーファイルで定義されています。
Note lpOverlapped パラメーターに NULL を指定して WSARecvMsg のようなブロッキングの Winsock 呼び出しを発行した場合、呼び出しが完了する前に Winsock がネットワークイベントを待機する必要が生じることがあります。この状況で Winsock はアラート可能な待機を行うため、同じスレッドでスケジュールされた非同期プロシージャ呼び出し (APC) によって中断される可能性があります。進行中のブロッキング Winsock 呼び出しを中断した APC の内部で、同じスレッド上でさらに別のブロッキング Winsock 呼び出しを発行すると未定義の動作となるため、Winsock クライアントは決してこれを試みてはなりません。
オーバーラップソケット I/O
オーバーラップ操作が即座に完了した場合、WSARecvMsg はゼロを返し、lpNumberOfBytesRecvd パラメーターは受信バイト数で更新され、lpFlags パラメーターが示すフラグビットも更新されます。オーバーラップ操作が正常に開始されて後で完了する場合、WSARecvMsg は SOCKET_ERROR を返し、エラーコード WSA_IO_PENDING を示します。この場合、lpNumberOfBytesRecvd は更新されません。オーバーラップ操作が完了すると、転送されたデータ量は、(指定されていれば) 完了ルーチンの cbTransferred パラメーター、または WSAGetOverlappedResult の lpcbTransfer パラメーターによって示されます。フラグの値は、WSAGetOverlappedResult の lpdwFlags パラメーターを調べることで取得します。
オーバーラップ I/O を使用する WSARecvMsg 関数は、先行する WSARecv、WSARecvFrom、WSARecvMsg、WSASend、WSASendMsg、WSASendTo の各関数の完了ルーチン内から呼び出すことができます。特定のソケットについて、I/O 完了ルーチンが入れ子になることはありません。これにより、時間的制約のあるデータ転送をプリエンプティブなコンテキスト内で完結させることができます。
lpOverlapped パラメーターは、オーバーラップ操作が継続している間ずっと有効でなければなりません。複数の I/O 操作を同時に実行中にする場合は、それぞれが個別の WSAOVERLAPPED 構造体を参照する必要があります。
lpCompletionRoutine パラメーターが NULL の場合、lpOverlapped の hEvent パラメーターに有効なイベントオブジェクトのハンドルが格納されていれば、オーバーラップ操作の完了時にそのイベントがシグナル状態になります。アプリケーションは WSAWaitForMultipleEvents または WSAGetOverlappedResult を使用して、そのイベントオブジェクトを待機またはポーリングできます。
lpCompletionRoutine が NULL でない場合、hEvent パラメーターは無視され、アプリケーションが完了ルーチンへコンテキスト情報を渡すために使用できます。NULL 以外の lpCompletionRoutine を渡した呼び出し元が、同じオーバーラップ I/O 要求に対して後から WSAGetOverlappedResult を呼び出す場合、その WSAGetOverlappedResult の呼び出しで fWait パラメーターを TRUE に設定してはなりません。この場合、hEvent パラメーターの用途は未定義であり、hEvent パラメーターを待機しようとすると予測できない結果になります。
完了ルーチンは、Windows のファイル I/O 完了ルーチンに規定されているものと同じ規則に従います。完了ルーチンは、スレッドがアラート可能な待機状態になるまで呼び出されません。これは、たとえば fAlertable パラメーターを TRUE に設定して WSAWaitForMultipleEvents 関数を呼び出した場合に発生します。
完了ルーチンのプロトタイプは次のとおりです。
void CALLBACK CompletionRoutine(
IN DWORD dwError,
IN DWORD cbTransferred,
IN LPWSAOVERLAPPED lpOverlapped,
IN DWORD dwFlags
);
CompletionRoutine は、アプリケーション定義またはライブラリ定義の関数名のプレースホルダーです。dwError パラメーターは、lpOverlapped パラメーターが示すオーバーラップ操作の完了状態を指定します。cbTransferred パラメーターは、受信したバイト数を指定します。dwFlags パラメーターには、受信操作が即座に完了していた場合に lpMsg パラメーターが指す WSAMSG 構造体の dwFlags メンバーにも返される情報が格納されます。CompletionRoutine 関数は値を返しません。
この関数から戻ると、このソケットに対する別の保留中の完了ルーチンを呼び出せるようになります。WSAWaitForMultipleEvents を使用している場合、アラート可能なスレッドの待機が戻り値 WSA_IO_COMPLETION で満たされる前に、待機中のすべての完了ルーチンが呼び出されます。完了ルーチンは任意の順序で呼び出される可能性があり、必ずしもオーバーラップ操作が完了した順序とは限りません。ただし、ポストされたバッファーは、指定された順序どおりに埋められることが保証されます。
I/O 完了ポートを使用している場合は、WSARecvMsg を呼び出した順序がバッファーへの格納順序にもなる点に注意してください。バッファーの順序が予測できなくなるため、同一のソケットに対して複数のスレッドから同時に WSARecvMsg を呼び出してはなりません。
Microsoft 公式リファレンス: 英語 (en-us) · 日本語 (ja-jp) · 原文ソース (GitHub)