LPWSPRECVFROM
コールバックシグネチャ
INT LPWSPRECVFROM(
SOCKET s,
WSABUF* lpBuffers,
DWORD dwBufferCount,
DWORD* lpNumberOfBytesRecvd,
DWORD* lpFlags,
SOCKADDR* lpFrom,
INT* lpFromlen,
OVERLAPPED* lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
WSATHREADID* lpThreadId,
INT* lpErrno
);パラメーター
| フィールド | 型 | 説明 |
|---|---|---|
| s | SOCKET | ソケットを識別する記述子です。 |
| lpBuffers | WSABUF* | WSABUF 構造体の配列へのポインターです。各 WSABUF 構造体には、バッファーへのポインターと、そのバッファーの長さ (バイト単位) が格納されます。 |
| dwBufferCount | DWORD | lpBuffers 配列に含まれる WSABUF 構造体の数です。 |
| lpNumberOfBytesRecvd | DWORD* | この呼び出しで受信したバイト数へのポインターです。 |
| lpFlags | DWORD* | フラグへのポインターです。 |
| lpFrom | SOCKADDR* | オーバーラップ操作の完了時に送信元アドレスを格納する sockaddr 構造体のバッファーへのポインターです (省略可能)。 |
| lpFromlen | INT* | lpFrom バッファーのサイズ (バイト単位) へのポインターです。lpFrom を指定した場合にのみ必要です。 |
| lpOverlapped | OVERLAPPED* | WSAOverlapped 構造体へのポインターです (非オーバーラップソケットでは無視されます)。 |
| lpCompletionRoutine | LPWSAOVERLAPPED_COMPLETION_ROUTINE | 受信操作が完了したときに呼び出される完了ルーチンへのポインターです (非オーバーラップソケットでは無視されます)。 |
| lpThreadId | WSATHREADID* | プロバイダーが後続の WPUQueueApc の呼び出しで使用する WSATHREADID 構造体へのポインターです。プロバイダーは、WPUQueueApc 関数から戻るまで、参照先の WSATHREADID 構造体 (そのポインターではなく構造体そのもの) を保存しておく必要があります。 |
| lpErrno | INT* | エラーコードへのポインターです。 |
公式ドキュメント
LPWSPRecvFrom 関数は、データグラムを受信し、送信元アドレスを格納します。
戻り値
エラーが発生せず、受信操作が直ちに完了した場合、LPWSPRecvFrom は 0 を返します。この場合、完了ルーチンが指定されていれば、それはすでにキューに登録されていることに注意してください。それ以外の場合は SOCKET_ERROR が返され、具体的なエラーコードを lpErrno から取得できます。エラーコード WSA_IO_PENDING は、オーバーラップ操作が正常に開始され、完了が後で通知されることを示します。それ以外のエラーコードは、オーバーラップ操作が開始されず、完了通知も発生しないことを示します。
| エラーコード | 意味 |
|---|---|
| ネットワークサブシステムで障害が発生しました。 | |
| lpFromlen パラメーターが無効です。lpFrom バッファーが小さすぎて相手のアドレスを格納できないか、lpbuffers がユーザーアドレス空間の有効な範囲内に完全には収まっていません。 | |
| (ブロッキング) 呼び出しが LPWSPCancelBlockingCall によってキャンセルされました。 | |
| ブロッキング Windows Sockets 呼び出しが進行中であるか、サービスプロバイダーがまだコールバック関数を処理しています。 | |
| ソケットがバインドされていない (たとえば LPWSPBind によるバインドが行われていない) か、ソケットがオーバーラップフラグ付きで作成されていません。 | |
| ソケットが接続済みです。この関数は、コネクション指向かコネクションレスかにかかわらず、接続済みのソケットでは使用できません。 | |
| 操作の実行中にキープアライブ動作によって障害が検出されたため、接続が切断されました。 | |
| 記述子がソケットではありません。 | |
| MSG_OOB が指定されましたが、ソケットが SOCK_STREAM 型などのストリーム型ではないか、このソケットに関連付けられた通信ドメインで OOB データがサポートされていないか、ソケットが単方向で送信操作のみをサポートしています。 | |
| ソケットがシャットダウンされています。how に SD_RECEIVE または SD_BOTH を指定して LPWSPShutdown を呼び出した後は、そのソケットで LPWSPRecvFrom を実行できません。 | |
|
**Windows NT:** オーバーラップソケットの場合: 未処理のオーバーラップ I/O 要求が多すぎます。非オーバーラップソケットの場合: ソケットが非ブロッキングとしてマークされており、受信操作を直ちに完了できません。 |
|
| メッセージが大きすぎて指定されたバッファーに収まりませんでした。また、(信頼性のないプロトコルの場合のみ) バッファーに収まらなかったメッセージの末尾部分は破棄されました。 | |
| リモート側がハードクローズまたは強制クローズを実行したため、仮想回線がリセットされました。ソケットは使用できなくなるため、アプリケーションはソケットを閉じる必要があります。UDP データグラムソケットの場合、このエラーは、直前の送信操作の結果として ICMP の "Port Unreachable" メッセージが返されたことを示します。 | |
| ソケット s はメッセージ指向であり、リモート側によって仮想回線が正常に閉じられました。 | |
| オーバーラップ操作が正常に開始され、完了は後で通知されます。 | |
| ソケットが閉じられたため、オーバーラップ操作がキャンセルされました。 |
解説(Remarks)
LPWSPRecvFrom 関数は、主に s で指定されるコネクションレスソケットで使用します。ソケットは接続されていてはなりません。ソケットのローカルアドレスは判明している必要があります。これは LPWSPBind によって明示的に行うことも、LPWSPSendTo または LPWSPJoinLeaf によって暗黙的に行うこともできます。
オーバーラップソケットの場合、この関数は、(接続済みの場合もある) ソケットで受信データが利用可能になったときにそのデータを格納するための 1 つ以上のバッファーをポストするために使用します。その後、クライアントが指定した完了通知 (完了ルーチンの呼び出し、またはイベントオブジェクトのシグナル設定) が行われます。操作が直ちに完了しない場合、最終的な完了状態は、完了ルーチンまたは LPWSPGetOverlappedResult を通じて取得します。また、lpFrom と lpFromlen が指す値は、完了が通知されるまで更新されないことにも注意してください。アプリケーションは、これらの値が更新されるまで使用したり変更したりしてはならないため、クライアントはこれらのパラメーターに自動変数 (つまりスタック上の変数) を使用してはなりません。
lpOverlapped と lpCompletionRoutine の両方が NULL の場合、この関数におけるソケットは非オーバーラップソケットとして扱われます。
非オーバーラップソケットの場合、lpOverlapped、lpCompletionRoutine、lpThreadId の各パラメーターは無視されます。トランスポートがすでに受信してバッファリングしているデータは、指定されたユーザーバッファーにコピーされます。ブロッキングソケットで、トランスポートが受信してバッファリングしたデータがまだない場合、この呼び出しは、LPWSPRecv に割り当てられたブロッキングセマンティクスに従ってデータを受信するまでブロックします。
指定されたバッファーは、lpBuffers が指す配列に現れる順序で埋められ、隙間ができないように詰めて格納されます。
lpBuffers パラメーターが指す WSABUF 構造体の配列は一時的なものです。この操作がオーバーラップ方式で完了する場合、この呼び出しから戻る前に WSABUF 構造体へのポインターのこの配列を取り込むのは、サービスプロバイダーの責任です。これにより、Windows Sockets SPI クライアントはスタック上に WSABUF の配列を構築できます。
コネクションレス型のソケットの場合、データの送信元アドレスが lpFrom の指すバッファーにコピーされます。入力時、lpFromlen が指す値はこのバッファーのサイズに初期化され、完了時には、そこに格納された実際のアドレスのサイズを示すように変更されます。
オーバーラップソケットについて前述したとおり、lpFrom と lpFromlen の各パラメーターは、オーバーラップ I/O が完了するまで更新されません。したがって、これらのパラメーターが指すメモリは、サービスプロバイダーから引き続き利用できる必要があり、Windows Sockets SPI クライアントのスタックフレーム上に確保することはできません。lpFrom と lpFromlen の各パラメーターは、コネクション指向のソケットでは無視されます。
バイトストリーム型のソケット (たとえば SOCK_STREAM 型) の場合、受信データは、バッファーが満たされるか、接続が閉じられるか、内部にバッファリングされたデータが尽きるまで、バッファーに格納されます。受信データがすべてのバッファーを満たすかどうかにかかわらず、オーバーラップソケットでは完了通知が発生します。
メッセージ指向のソケットの場合、指定されたバッファーの合計サイズを上限として、1 つの受信メッセージが指定されたバッファーに格納され、オーバーラップソケットでは完了通知が発生します。メッセージが指定されたバッファーより大きい場合、バッファーにはメッセージの先頭部分が格納されます。サービスプロバイダーが MSG_PARTIAL 機能をサポートしている場合、そのソケットについて lpFlags に MSG_PARTIAL フラグが設定され、後続の受信操作でメッセージの残りを取得できます。MSG_PARTIAL がサポートされていないものの、プロトコルが信頼性のあるものである場合、LPWSPRecvFrom はエラー WSAEMSGSIZE を生成し、より大きなバッファーを使用した後続の受信操作でメッセージ全体を取得できます。それ以外の場合 (つまり、プロトコルが信頼性のないもので、MSG_PARTIAL をサポートしていない場合) は、あふれたデータは失われ、LPWSPRecvFrom はエラー WSAEMSGSIZE を生成します。
lpFlags パラメーターを使用すると、対象のソケットに指定されたオプションに加えて、この関数呼び出しの動作に影響を与えることができます。つまり、この関数のセマンティクスは、ソケットオプションと lpFlags パラメーターによって決まります。後者は、次の値をビットごとの OR 演算子で組み合わせて構成します。
| 値 | 意味 |
|---|---|
| MSG_PEEK | 受信データを覗き見します。データはバッファーにコピーされますが、入力キューからは削除されません。このフラグは非オーバーラップソケットでのみ有効です。 |
| MSG_OOB | 帯域外 (OOB) データを処理します。 |
| MSG_PARTIAL | このフラグはメッセージ指向のソケットでのみ使用します。出力時には、渡されたデータが送信側から送信されたメッセージの一部であることを示します。メッセージの残りの部分は、後続の受信操作で渡されます。MSG_PARTIAL フラグがクリアされた後続の受信操作は、送信側のメッセージの終わりを示します。入力パラメーターとして指定した場合、MSG_PARTIAL は、サービスプロバイダーがメッセージの一部しか受信していなくても受信操作を完了すべきであることを示します。 |
メッセージ指向のソケットの場合、部分的なメッセージを受信すると、lpFlags パラメーターに MSG_PARTIAL ビットが設定されます。完全なメッセージを受信した場合、lpFlags の MSG_PARTIAL はクリアされます。完了が遅延する場合、lpFlags が指す値は更新されません。完了が通知されたら、Windows Sockets SPI クライアントは LPWSPGetOverlappedResult を呼び出し、lpdwFlags パラメーターが指すフラグを確認する必要があります。
オーバーラップ操作が直ちに完了した場合、LPWSPRecv は 0 を返し、lpNumberOfBytesRecvd パラメーターが受信したバイト数で更新され、lpFlags パラメーターが指すフラグビットも更新されます。オーバーラップ操作が正常に開始され、後で完了する場合、LPWSPRecv は SOCKET_ERROR を返し、エラーコード WSA_IO_PENDING を示します。この場合、lpNumberOfBytesRecvd と lpFlags は更新されません。オーバーラップ操作が完了すると、転送されたデータ量は、(指定されている場合は) 完了ルーチンの cbTransferred パラメーター、または LPWSPGetOverlappedResult の lpcbTransfer パラメーターによって通知されます。フラグの値は、LPWSPGetOverlappedResult の lpdwFlags パラメーターを調べることで取得します。
プロバイダーは、先行する LPWSPRecv、LPWSPRecvFrom、LPWSPSend、LPWSPSendTo の各関数の完了ルーチン内からこの関数を呼び出せるようにする必要があります。ただし、特定のソケットについて、I/O 完了ルーチンを入れ子にすることはできません。これにより、時間的制約のあるデータ送信を、プリエンプティブなコンテキスト内で完結させることができます。
lpOverlapped パラメーターは、オーバーラップ操作が続いている間、有効である必要があります。複数の I/O 操作を同時に実行する場合は、それぞれが別々のオーバーラップ構造体を参照する必要があります。WSAOverlapped 構造体については、専用のリファレンスページで説明しています。
lpCompletionRoutine パラメーターが NULL の場合、lpOverlapped の hEvent メンバーに有効なイベントオブジェクトのハンドルが格納されていれば、サービスプロバイダーは、オーバーラップ操作の完了時にそのメンバーをシグナル状態にします。Windows Sockets SPI クライアントは、LPWSPGetOverlappedResult を使用して、イベントオブジェクトを待機またはポーリングできます。
lpCompletionRoutine が NULL でない場合、hEvent メンバーは無視され、Windows Sockets SPI クライアントが完了ルーチンにコンテキスト情報を渡すために使用できます。オーバーラップ操作の完了時に、クライアントが指定した完了ルーチンを呼び出す手配をするのは、サービスプロバイダーの責任です。完了ルーチンは、オーバーラップ操作を開始したスレッドと同じスレッドのコンテキストで実行する必要があるため、サービスプロバイダーから直接呼び出すことはできません。Ws2_32.dll は、完了ルーチンの呼び出しを容易にするために、非同期プロシージャ呼び出し (APC) のメカニズムを提供しています。
サービスプロバイダーは、WPUQueueApc を呼び出すことで、適切なスレッドおよびプロセスのコンテキストで関数が実行されるように手配します。この関数は任意のプロセスおよびスレッドのコンテキストから呼び出すことができ、オーバーラップ操作の開始に使用されたスレッドやプロセスとは異なるコンテキストであってもかまいません。
WPUQueueApc は、入力パラメーターとして、WSATHREADID 構造体へのポインター (lpThreadId 入力パラメーターによってプロバイダーに渡されたもの)、呼び出す APC 関数へのポインター、および後で APC 関数に渡されるコンテキスト値を受け取ります。利用できるコンテキスト値は 1 つだけであるため、APC 関数自体をクライアント指定の完了ルーチンにすることはできません。代わりにサービスプロバイダーは、渡されたコンテキスト値を使用してオーバーラップ操作に必要な結果情報にアクセスし、その後クライアント指定の完了ルーチンを呼び出す、独自の APC 関数へのポインターを渡す必要があります。
クライアントが用意する完了ルーチンのプロトタイプは次のとおりです。
void CALLBACK
CompletionRoutine(
IN DWORD dwError,
IN DWORD cbTransferred,
IN LPWSAOVERLAPPED lpOverlapped,
IN DWORD dwFlags
);
CompletionRoutine は、クライアントが指定する関数名のプレースホルダーです。dwError は、lpOverlapped が示すオーバーラップ操作の完了状態を表します。cbTransferred は、受信したバイト数を表します。dwFlags には、受信操作が直ちに完了していた場合に lpFlags に格納されたはずの情報が入ります。この関数は値を返しません。
完了ルーチンは任意の順序で呼び出される可能性があり、必ずしもオーバーラップ操作が完了した順序と同じとは限りません。ただし、ポストされたバッファーは、指定された順序で埋められることが保証されます。
指定したスレッドが終了すると、そのスレッドが開始したすべての I/O はキャンセルされます。オーバーラップソケットの場合、操作が完了する前にスレッドが閉じられると、保留中の非同期操作が失敗することがあります。詳細については、ExitThread を参照してください。
Microsoft 公式リファレンス: 英語 (en-us) · 日本語 (ja-jp) · 原文ソース (GitHub)