WSARecv 関数 (winsock2.h)
WSARecv 関数は、接続されたソケットまたはバインドされたコネクションレス ソケットからデータを受け取ります。
構文
int WSAAPI WSARecv(
[in] SOCKET s,
[in, out] LPWSABUF lpBuffers,
[in] DWORD dwBufferCount,
[out] LPDWORD lpNumberOfBytesRecvd,
[in, out] LPDWORD lpFlags,
[in] LPWSAOVERLAPPED lpOverlapped,
[in] LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);
パラメーター
[in] s
接続されているソケットを識別する記述子。
[in, out] lpBuffers
WSABUF 構造体の配列へのポインター。 各 WSABUF 構造体には、バッファーへのポインターと、バッファーの長さ (バイト単位) が含まれます。
[in] dwBufferCount
lpBuffers 配列内の WSABUF 構造体の数。
[out] lpNumberOfBytesRecvd
受信操作が直ちに完了した場合に、この呼び出しによって受信されたデータの数 (バイト単位) へのポインター。
lpOverlapped パラメーターが NULL でない場合は、このパラメーターに NULL を使用して、誤った結果を回避します。 このパラメーターは、lpOverlapped パラメーターが NULL でない場合にのみ NULL にすることができます。
[in, out] lpFlags
WSARecv 関数呼び出しの動作を変更するために使用されるフラグへのポインター。 詳細については、「解説」を参照してください。
[in] lpOverlapped
WSAOVERLAPPED 構造体へのポインター (オーバーラップされていないソケットの場合は無視されます)。
[in] lpCompletionRoutine
種類: _In_opt_ LPWSAOVERLAPPED_COMPLETION_ROUTINE
受信操作が完了したときに呼び出される完了ルーチンへのポインター (オーバーラップされていないソケットの場合は無視されます)。
戻り値
エラーが発生せず、受信操作がすぐに完了した場合、 WSARecv は 0 を返します。 この場合、呼び出し元のスレッドがアラート可能な状態になると、完了ルーチンが既に呼び出されるようにスケジュールされています。 それ以外の場合は、 SOCKET_ERROR の値が返され、 WSAGetLastError を呼び出すことによって特定のエラー コードを取得できます。 エラー コード WSA_IO_PENDING は、重複した操作が正常に開始され、その完了が後で示されることを示します。 その他のエラー コードは、重複した操作が正常に開始されず、完了の兆候が発生しないことを示します。
エラー コード | 意味 |
---|---|
仮想回線はタイムアウトまたはその他の障害のために切断されました。 | |
ストリーム ソケットの場合、仮想回線はリモート側によってリセットされました。 ソケットが使用できないため、アプリケーションはソケットを閉じる必要があります。 UDP データグラム ソケットの場合、このエラーは、以前の送信操作で ICMP "ポートに到達できません" メッセージが発生したことを示します。 | |
ソケット s はメッセージ指向であり、仮想回線はリモート側で正常に閉じられました。 | |
lpBuffers パラメーターは、ユーザー・アドレス・スペースの有効な部分に完全には含まれていません。 | |
ブロックしている Windows Sockets 1.1 呼び出しが進行中であるか、サービス プロバイダーがコールバック関数を処理しています。 | |
(ブロッキング) 呼び出しは WSACancelBlockingCall 関数によって取り消されました。 | |
ソケットがバインドされていません (バインドなど)。 | |
メッセージが大きすぎて指定されたバッファーに収まりきらず、(信頼性の低いプロトコルの場合のみ) バッファーに収まらないメッセージの末尾部分は破棄されました。 | |
ネットワーク サブシステムが失敗しました。 | |
接続指向ソケットの場合、このエラーは、操作の進行中に障害を検出した キープアライブ アクティビティが原因で接続が切断されたことを示します。 データグラム ソケットに関して、このエラーは有効期限が切れたことを示します。 | |
ソケットは接続されていません。 | |
記述子はソケットではありません。 | |
MSG_OOB が指定されましたが、ソケットは、型SOCK_STREAMなどのストリーム スタイルではありません。OOB データは、このソケットに関連付けられている通信ドメインでサポートされていないか、ソケットが一方向であり、送信操作のみをサポートします。 | |
ソケットがシャットダウンされました。SD_RECEIVEまたはSD_BOTHに設定された方法でシャットダウンが呼び出された後、ソケットで WSARecv を呼び出すことはできません。 | |
ネットワーク障害が発生したか、ピア システムが応答できなかったため、接続は切断されました。 | |
Windows NT: 重複するソケット: 未解決の重複した I/O 要求が多すぎます。 オーバーラップされていないソケット: ソケットは非ブロッキングとしてマークされ、受信操作をすぐに完了することはできません。 |
|
この関数を使用する前に、 WSAStartup 呼び出しが正常に行われる必要があります。 | |
重複した操作が正常に開始され、完了は後で示されます。 | |
ソケットが閉じられ、重複する操作が取り消されました。 |
解説
WSARecv 関数には、次の 3 つの重要な領域の標準 recv 関数と比較して、いくつかの追加機能が用意されています。
- 重複するソケットと組み合わせて使用して、重複する recv 操作を実行できます。
- これにより、複数の受信バッファーを指定できるため、I/O の分散/収集タイプに適用できます。
- lpFlags パラメーターは、入力時と出力時の両方で使用されるため、アプリケーションはMSG_PARTIAL フラグ ビットの出力状態を検出できます。 ただし、 MSG_PARTIAL フラグ ビットはすべてのプロトコルでサポートされているわけではありません。
接続されたコネクションレス ソケットの場合、この関数は、受信したメッセージが受け入れられるアドレスを制限します。 関数は、接続で指定されたリモート アドレスからのみメッセージを返します。 他のアドレスからのメッセージは (サイレント) 破棄されます。
重複するソケットの場合、 WSARecv を使用して、受信データが使用可能になったときに受信データが配置される 1 つ以上のバッファーをポストし、その後、アプリケーション指定の完了表示 (完了ルーチンの呼び出しまたはイベント オブジェクトの設定) が発生します。 操作がすぐに完了しない場合は、完了ルーチンまたは WSAGetOverlappedResult を使用して最終的な完了状態が取得されます。
オーバーラップされていないソケットの場合、ブロッキング セマンティクスは標準 の recv 関数と同じであり、 lpOverlapped パラメーターと lpCompletionRoutine パラメーターは無視されます。 トランスポートによって既に受信およびバッファーされたデータは、指定されたユーザー バッファーにコピーされます。 トランスポートによって現在受信およびバッファーされたデータがないブロッキング ソケットの場合、データが受信されるまで呼び出しはブロックされます。 Windows ソケット 2 では、この関数の標準的なブロック タイムアウト メカニズムは定義されていません。 バイト ストリーム プロトコルとして機能するプロトコルの場合、スタックは、使用可能なバッファー領域と使用可能な受信データの量に応じて、可能な限り多くのデータを返そうとします。 ただし、呼び出し元のブロックを解除するには、1 バイトの受信で十分です。 1 バイト以上が返される保証はありません。 メッセージ指向として機能するプロトコルの場合、呼び出し元のブロックを解除するには、完全なメッセージが必要です。
XP1_MESSAGE_ORIENTED | XP1_PSEUDO_STREAM | MSG_PARTIAL | として機能する |
---|---|---|---|
設定しない | * | * | バイト ストリーム |
* | オン | * | バイト ストリーム |
set | 未設定 | set | バイト ストリーム |
set | 未設定 | 設定しない | メッセージ指向 |
バッファーは lpBuffers が指す配列に表示される順序で塗りつぶされ、バッファーは穴が作成されないようパックされます。
この関数が重複して完了した場合、この呼び出しから戻る前に WSABUF 構造体をキャプチャするのは Winsock サービス プロバイダーの責任です。 これにより、アプリケーションは lpBuffers パラメーターによって指されるスタック ベースの WSABUF 配列を構築できます。
バイト ストリーム スタイルのソケット (たとえば、 SOCK_STREAM型) の場合、バッファーが入力されるか、接続が閉じられるか、内部バッファーに格納されたデータが使い果たされるまで、受信データがバッファーに配置されます。 受信データがすべてのバッファーを満たすかどうかに関係なく、重複するソケットに対して完了の兆候が発生します。
メッセージ指向ソケット (例: SOCK_DGRAM) の場合、受信メッセージはバッファーの合計サイズまでのバッファーに配置され、重複したソケットに対して完了の表示が発生します。 メッセージがバッファーより大きい場合、バッファーにはメッセージの最初の部分が入力されます。 MSG_PARTIAL機能が基になるサービス プロバイダーによってサポートされている場合は、lpFlags でMSG_PARTIAL フラグが設定され、後続の受信操作によってメッセージの残りの部分が取得されます。 MSG_PARTIALがサポートされていないが、プロトコルが信頼できる場合、WSARecv はエラー WSAEMSGSIZE を生成し、より大きなバッファーを持つ後続の受信操作を使用してメッセージ全体を取得できます。 それ以外の場合(プロトコルは信頼性が低く、 MSG_PARTIALをサポートしていません)、余分なデータが失われ、 WSARecv によってエラー WSAEMSGSIZE が生成されます。
接続指向ソケットの場合、 WSARecv は、ソケットがバイト・ストリームであるかメッセージ指向であるかに依存する 2 つの方法のいずれかで、仮想回線の正常終了を示すことができます。 バイト ストリームの場合、0 バイトが読み取られた (成功を示す戻り値が 0 で示され、 lpNumberOfBytesRecvd 値が 0) は正常終了を示し、それ以上のバイトは読み取られないことを示します。 多くの場合、0 バイト のメッセージが許容されるメッセージ指向ソケットの場合、 WSAEDISCON のエラー コードによるエラーが、正常なクローズを示すために使用されます。 いずれの場合も、 WSAECONNRESET の戻りエラー コードは、中止終了が発生したことを示します。
lpFlags パラメーターを使用すると、関連付けられたソケットに指定されたオプションを超えて、関数呼び出しの動作に影響を与えることができます。 つまり、この関数のセマンティクスは、ソケット オプションと lpFlags パラメーターによって決定されます。 後者は、次の表に示す値のいずれかでビットごとの OR 演算子を使用して構築されます。
値 | 説明 |
---|---|
MSG_PEEK |
受信データをピークします。 データはバッファーにコピーされますが、入力キューからは削除されません。
このフラグは、オーバーラップされていないソケットに対してのみ有効です。 |
MSG_OOB | OOB データを処理します。 |
MSG_PARTIAL |
このフラグは、メッセージ指向ソケット専用です。 出力時に、このフラグは、指定されたデータが送信者によって送信されるメッセージの一部であることを示します。 メッセージの残りの部分は、後続の受信操作で指定されます。 MSG_PARTIAL フラグがクリアされた後続の受信操作は、送信者のメッセージの終了を示します。
入力パラメーターとして、このフラグは、メッセージの一部のみがトランスポート プロバイダーによって受信された場合でも、受信操作を完了する必要があることを示します。 |
MSG_PUSH_IMMEDIATE |
このフラグは、ストリーム指向のソケット専用です。 このフラグを使用すると、ストリーム ソケットを使用するアプリケーションは、部分的に入力された保留中の受信要求の完了を遅延しないようにトランスポート プロバイダーに指示できます。 これは、転送中のデータの残りの部分を必ずしも待たずに、アプリケーションが受信データをできるだけ早く受け取る意思があることをトランスポート プロバイダーに示すヒントです。 部分的に入力された保留中の受信要求を構成するものは、トランスポート固有の問題です。
TCP の場合、これは受信 TCP セグメントが受信要求データ バッファーに配置されている場合を指し、どの TCP セグメントも PUSH ビット値 1 を示していません。 この場合、TCP は、PUSH ビットが 1 に設定された TCP セグメントでデータの残りの部分が到着できるように、部分的に入力された受信要求をもう少し長く保持できます。 このフラグは、受信要求を保持するのではなく、すぐに完了するように TCP に指示します。 部分ブロックの処理は多くの場合、最適ではないため、大きなブロック転送にこのフラグを使用することはお勧めしません。 このフラグは、部分データの受信と処理がすぐに処理待ち時間を短縮するのに役立つ場合にのみ役立ちます。 このフラグは、実際の保証ではなくヒントです。 このフラグは、Windows 8.1、Windows Server 2012 R2 以降でサポートされています。 |
MSG_WAITALL |
受信要求は、次のいずれかのイベントが発生した場合にのみ完了します。
基になるトランスポート プロバイダーが MSG_WAITALLをサポートしていない場合、またはソケットが非ブロッキング モードの場合、この呼び出しは WSAEOPNOTSUPP で失敗します。 また、 MSG_WAITALL が MSG_OOB、 MSG_PEEK、または MSG_PARTIALと共に指定されている場合、この呼び出しは WSAEOPNOTSUPP で失敗します。 このフラグは、データグラム・ソケットまたはメッセージ指向ソケットではサポートされていません。 |
メッセージ指向ソケットの場合、部分的なメッセージを受信した場合、lpFlags パラメーターにMSG_PARTIAL ビットが設定されます。 完全なメッセージを受信すると、lpFlags でMSG_PARTIALがクリアされます。 遅延完了の場合、 lpFlags が指す値は更新されません。 完了が示されたら、アプリケーションは WSAGetOverlappedResult を呼び出し、 lpdwFlags パラメーターによって示されるフラグを調べる必要があります。
重複するソケット I/O
重複した操作がすぐに完了すると、 WSARecv は 0 の値を返し、 lpNumberOfBytesRecvd パラメーターは受信したバイト数で更新され、 lpFlags パラメーターによって示されるフラグ ビットも更新されます。 重複した操作が正常に開始され、後で完了する場合、 WSARecv は SOCKET_ERRORを 返し、エラー コード WSA_IO_PENDINGを示します。 この場合、 lpNumberOfBytesRecvd と lpFlags は更新されません。 重複する操作が完了すると、転送されるデータの量は、完了ルーチンの cbTransferred パラメーター (指定されている場合) または WSAGetOverlappedResult の lpcbTransfer パラメーターを使用して示されます。 フラグ値は、WSAGetOverlappedResult の lpdwFlags パラメーターを調べることによって取得されます。重複した I/O を使用する WSARecv 関数は、以前の WSARecv、WSARecvFrom、WSASend、または 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 パラメーターには、受信操作がすぐに完了した場合に lpFlags に表示される情報が含まれます。 この関数は値を返しません。
この関数から戻って、このソケットに対して別の保留中の完了ルーチンを呼び出すことができます。 WSAWaitForMultipleEvents を使用する場合、警告可能なスレッドの待機がWSA_IO_COMPLETIONのリターン コードで満たされる前に、すべての待機完了ルーチンが呼び出されます。 完了ルーチンは任意の順序で呼び出すことができます。重複する操作が完了した順序は必ずしも同じではありません。 ただし、ポストされたバッファーは、指定した順序と同じ順序で入力することが保証されます。
I/O 完了ポートを使用している場合は、 WSARecv に対する呼び出しの順序もバッファーが設定される順序であることに注意してください。 WSARecv は、異なるスレッドから同じソケットで同時に呼び出さないでください。これは、予期しないバッファー順序が発生する可能性があるためです。
コード例
次の例は、重複した I/O モードで WSARecv 関数を使用する方法を示しています。#ifndef UNICODE
#define UNICODE
#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <Windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <stdlib.h>
// Need to link with Ws2_32.lib
#pragma comment(lib, "ws2_32.lib")
#pragma warning(disable: 4127) // Conditional expression is a constant
#define DATA_BUFSIZE 4096
int __cdecl main(int argc, char **argv)
{
WSADATA wsd;
struct addrinfo *result = NULL, *ptr = NULL, hints;
WSAOVERLAPPED RecvOverlapped;
SOCKET ConnSocket = INVALID_SOCKET;
WSABUF DataBuf;
DWORD RecvBytes, Flags;
char buffer[DATA_BUFSIZE];
int err = 0;
int rc;
if (argc != 2) {
wprintf(L"usage: %s server-name\n", argv[0]);
return 1;
}
// Load Winsock
rc = WSAStartup(MAKEWORD(2, 2), &wsd);
if (rc != 0) {
wprintf(L"Unable to load Winsock: %d\n", rc);
return 1;
}
// Make sure the hints struct is zeroed out
SecureZeroMemory((PVOID) & hints, sizeof (struct addrinfo));
// Initialize the hints to retrieve the server address for IPv4
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
rc = getaddrinfo(argv[1], "27015", &hints, &result);
if (rc != 0) {
wprintf(L"getaddrinfo failed with error: %d\n", rc);
return 1;
}
for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {
ConnSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
if (ConnSocket == INVALID_SOCKET) {
wprintf(L"socket failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
return 1;
}
rc = connect(ConnSocket, ptr->ai_addr, (int) ptr->ai_addrlen);
if (rc == SOCKET_ERROR) {
if (WSAECONNREFUSED == (err = WSAGetLastError())) {
closesocket(ConnSocket);
ConnSocket = INVALID_SOCKET;
continue;
}
wprintf(L"connect failed with error: %d\n", err);
freeaddrinfo(result);
closesocket(ConnSocket);
return 1;
}
break;
}
if (ConnSocket == INVALID_SOCKET) {
wprintf(L"Unable to establish connection with the server!\n");
freeaddrinfo(result);
return 1;
}
wprintf(L"Client connected...\n");
// Make sure the RecvOverlapped struct is zeroed out
SecureZeroMemory((PVOID) & RecvOverlapped, sizeof (WSAOVERLAPPED));
// Create an event handle and setup an overlapped structure.
RecvOverlapped.hEvent = WSACreateEvent();
if (RecvOverlapped.hEvent == NULL) {
wprintf(L"WSACreateEvent failed: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ConnSocket);
return 1;
}
DataBuf.len = DATA_BUFSIZE;
DataBuf.buf = buffer;
// Call WSARecv until the peer closes the connection
// or until an error occurs
while (1) {
Flags = 0;
rc = WSARecv(ConnSocket, &DataBuf, 1, &RecvBytes, &Flags, &RecvOverlapped, NULL);
if ((rc == SOCKET_ERROR) && (WSA_IO_PENDING != (err = WSAGetLastError()))) {
wprintf(L"WSARecv failed with error: %d\n", err);
break;
}
rc = WSAWaitForMultipleEvents(1, &RecvOverlapped.hEvent, TRUE, INFINITE, TRUE);
if (rc == WSA_WAIT_FAILED) {
wprintf(L"WSAWaitForMultipleEvents failed with error: %d\n", WSAGetLastError());
break;
}
rc = WSAGetOverlappedResult(ConnSocket, &RecvOverlapped, &RecvBytes, FALSE, &Flags);
if (rc == FALSE) {
wprintf(L"WSARecv operation failed with error: %d\n", WSAGetLastError());
break;
}
wprintf(L"Read %d bytes\n", RecvBytes);
WSAResetEvent(RecvOverlapped.hEvent);
// If 0 bytes are received, the connection was closed
if (RecvBytes == 0)
break;
}
WSACloseEvent(RecvOverlapped.hEvent);
closesocket(ConnSocket);
freeaddrinfo(result);
WSACleanup();
return 0;
}
Windows Phone 8: この関数は、Windows Phone 8 以降の Windows Phone ストア アプリでサポートされています。
Windows 8.1と Windows Server 2012 R2: この関数は、Windows 8.1、Windows Server 2012 R2 以降の Windows ストア アプリでサポートされています。
要件
サポートされている最小のクライアント | Windows 8.1、Windows Vista [デスクトップ アプリ |UWP アプリ] |
サポートされている最小のサーバー | Windows Server 2003 [デスクトップ アプリのみ | UWP アプリ] |
対象プラットフォーム | Windows |
ヘッダー | winsock2.h |
Library | Ws2_32.lib |
[DLL] | Ws2_32.dll |