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 ソケット 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機能が基になるサービス プロバイダーによってサポートされている場合、MSG_PARTIAL フラグは lpFlags で設定され、後続の受信操作ではメッセージの残りの部分が取得されます。 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 |