WSARecvFrom 関数 (winsock2.h)

WSARecvFrom 関数はデータグラムを受け取り、ソース アドレスを格納します。

構文

int WSAAPI WSARecvFrom(
  [in]      SOCKET                             s,
  [in, out] LPWSABUF                           lpBuffers,
  [in]      DWORD                              dwBufferCount,
  [out]     LPDWORD                            lpNumberOfBytesRecvd,
  [in, out] LPDWORD                            lpFlags,
  [out]     sockaddr                           *lpFrom,
  [in, out] LPINT                              lpFromlen,
  [in]      LPWSAOVERLAPPED                    lpOverlapped,
  [in]      LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);

パラメーター

[in] s

ソケットを識別する記述子。

[in, out] lpBuffers

WSABUF 構造体の配列へのポインター。 各 WSABUF 構造体には、バッファーへのポインターとバッファーの長さが含まれます。

[in] dwBufferCount

lpBuffers 配列内の WSABUF 構造体の数。

[out] lpNumberOfBytesRecvd

WSARecvFrom 操作が直ちに完了した場合に、この呼び出しで受信したバイト数へのポインター。

lpOverlapped パラメーターが NULL でない場合は、このパラメーターに NULL を使用して、誤った結果を回避します。 このパラメーターは、lpOverlapped パラメーターが NULL でない場合にのみ NULL にすることができます。

[in, out] lpFlags

WSARecvFrom 関数呼び出しの動作を変更するために使用されるフラグへのポインター。 以下の解説を参照してください。

[out] lpFrom

重複する操作の完了時にソース アドレスを保持するバッファーへの省略可能なポインター。

[in, out] lpFromlen

lpFrom が指定されている場合にのみ必要な "from" バッファーのサイズ (バイト単位) へのポインター。

[in] lpOverlapped

WSAOVERLAPPED 構造体へのポインター (オーバーラップされていないソケットの場合は無視されます)。

[in] lpCompletionRoutine

種類: _In_opt_ LPWSAOVERLAPPED_COMPLETION_ROUTINE

WSARecvFrom 操作が完了したときに呼び出される完了ルーチンへのポインター (オーバーラップされていないソケットの場合は無視されます)。

戻り値

エラーが発生せず、受信操作がすぐに完了した場合、 WSARecvFrom は 0 を返します。 この場合、呼び出し元のスレッドがアラート可能な状態になると、完了ルーチンが既に呼び出されるようにスケジュールされています。 それ以外の場合は、 SOCKET_ERROR の値が返され、 WSAGetLastError を呼び出すことによって特定のエラー コードを取得できます。 エラー コード WSA_IO_PENDING は、重複した操作が正常に開始され、その完了が後で示されることを示します。 その他のエラー コードは、重複した操作が正常に開始されず、完了の兆候が発生しないことを示します。

エラー コード 意味
WSAECONNRESET
強制終了または中止になる閉じる操作を実行するリモート側によって仮想回線がリセットされました。 ソケットが使用できないため、アプリケーションはソケットを閉じる必要があります。 UPD データグラム ソケットの場合、このエラーは、以前の送信操作で ICMP "ポート到達不能" メッセージが発生したことを示します。
WSAEFAULT
lpBufferslpFlagslpFromlpNumberOfBytesRecvdlpFromlenlpOverlapped、または lpCompletionRoutine パラメーターは、ユーザー アドレス空間の有効な部分に完全に含まれていません。lpFrom バッファーが小さすぎてピア アドレスに対応できませんでした。
WSAEINPROGRESS
ブロックしている Windows Sockets 1.1 呼び出しが進行中であるか、サービス プロバイダーがコールバック関数を処理しています。
WSAEINTR
WSACancelBlockingCall を使用して、Windows Socket 1.1 の呼び出しをブロックしているが取り消されました。
WSAEINVAL
ソケットがバインドされていません ( バインドありなど)。
WSAEMSGSIZE
指定したバッファーに対してメッセージが大きすぎて、バッファーに収まらないメッセージの末尾部分が破棄されました (信頼性の低いプロトコルの場合のみ)。
WSAENETDOWN
ネットワーク サブシステムが失敗しました。
WSAENETRESET
データグラム ソケットに関して、このエラーは有効期限が切れたことを示します。
WSAENOTCONN
ソケットが接続されていません (接続指向のソケットのみ)。
WSAEWOULDBLOCK
Windows NT:

重複するソケット: 未解決の重複した I/O 要求が多すぎます。 オーバーラップされていないソケット: ソケットは非ブロッキングとしてマークされ、受信操作をすぐに完了することはできません。

WSANOTINITIALIZED
この関数を使用する前に、 WSAStartup 呼び出しが正常に行われる必要があります。
WSA_IO_PENDING
重複した操作が正常に開始され、完了が後で示されます。
WSA_OPERATION_ABORTED
ソケットが閉じられ、重複する操作が取り消されました。

解説

WSARecvFrom 関数は、次の 3 つの重要な領域で標準 recvfrom 関数以上の機能を提供します。

  • これは、重複するソケットと組み合わせて使用して、重複する受信操作を実行できます。
  • これにより、複数の受信バッファーを指定できるため、I/O の分散/収集タイプに適用できます。
  • lpFlags パラメーターは入力パラメーターと出力パラメーターの両方であり、アプリケーションはMSG_PARTIAL フラグ ビットの出力状態を検出できます。 MSG_PARTIAL フラグ ビットはすべてのプロトコルでサポートされていないことに注意してください。
WSARecvFrom 関数は、主に で指定されたコネクションレス ソケットで使用されます。 ソケットのローカル アドレスは既知である必要があります。 サーバー アプリケーションの場合、これは通常、 バインドによって明示的に行われます。 クライアント アプリケーションでは、明示的なバインドは推奨されません。 この関数を使用するクライアント アプリケーションの場合、ソケットは sendtoWSASendTo、または WSAJoinLeaf を介してローカル アドレスに暗黙的にバインドされる可能性があります。

重複するソケットの場合、この関数は、受信データが (接続されている可能性がある) ソケットで使用可能になった後に、アプリケーション指定の完了表示 (完了ルーチンの呼び出しまたはイベント オブジェクトの設定) が発生した後に、受信データが配置される 1 つ以上のバッファーをポストするために使用されます。 操作がすぐに完了しない場合は、完了ルーチンまたは WSAGetOverlappedResult を使用して最終的な完了状態が取得されます。 また、lpFrom および lpFromlen で示される値は、完了が示されるまで更新されません。 アプリケーションは、更新されるまで、これらの値を使用したり、応答したりしてはなりません。そのため、アプリケーションでは、これらのパラメーターに自動 (つまりスタック ベース) 変数を使用しないでください。

メモ 特定のスレッドによって開始されたすべての I/O は、そのスレッドが終了すると取り消されます。 重複するソケットの場合、保留中の非同期操作は、操作が完了する前にスレッドが閉じられた場合に失敗する可能性があります。 詳細については、「 ExitThread 」を参照してください。
 
lpOverlappedlpCompletionRoutine の両方が NULL の場合、この関数のソケットは、オーバーラップされていないソケットとして扱われます。

オーバーラップされていないソケットの場合、ブロッキング セマンティクスは標準 の WSARecv 関数と同じであり、 lpOverlapped パラメーターと lpCompletionRoutine パラメーターは無視されます。 トランスポートによって既に受信およびバッファーされたデータは、ユーザー バッファーにコピーされます。 トランスポートによって現在受信およびバッファーされたデータがないブロッキング ソケットの場合、データが受信されるまで呼び出しはブロックされます。

バッファーは lpBuffers で示される配列に表示される順序で入力され、バッファーは穴が作成されないようパックされます。

この関数が重複して完了した場合、この呼び出しから戻る前に WSABUF 構造体をキャプチャするのは Winsock サービス プロバイダーの責任です。 これにより、アプリケーションは lpBuffers パラメーターによって指されるスタック ベースの WSABUF 配列を構築できます。

コネクションレス・ソケット・タイプの場合、データの発信元のアドレスは lpFrom で示されるバッファーにコピーされます。 lpFromlen が指す値は、このバッファーのサイズに初期化され、完了時に変更され、そこに格納されているアドレスの実際のサイズを示します。 重複するソケットについて前述したように、 lpFrom パラメーターと lpFromlen パラメーターは、重複した I/O が完了するまで更新されません。 したがって、これらのパラメーターが指すメモリは、サービス プロバイダーが引き続き使用でき、アプリケーション スタック フレームに割り当てることはできません。 接続指向ソケットの 場合、lpFrom パラメーターと lpFromlen パラメーターは無視されます。

バイト ストリーム スタイルのソケット (たとえば、「SOCK_STREAM」と入力) の場合、受信データは次のまでバッファーに配置されます。

  • バッファーが塗りつぶされます。
  • 接続が閉じています。
  • 内部的にバッファーに格納されたデータが使い果たされます。
受信データがすべてのバッファーを満たすかどうかに関係なく、重複するソケットに対して完了の兆候が発生します。 メッセージ指向ソケットの場合、受信メッセージはバッファーの合計サイズまでバッファーに入れられ、重複したソケットに対して完了表示が発生します。 メッセージがバッファーより大きい場合、バッファーにはメッセージの最初の部分が入力されます。 MSG_PARTIAL機能が基になるサービス プロバイダーによってサポートされている場合、MSG_PARTIAL フラグは lpFlags で設定され、後続の受信操作はメッセージの残りの部分を取得します。 MSG_PARTIALがサポートされていないが、プロトコルが信頼できる場合、WSARecvFrom はエラー WSAEMSGSIZE を生成し、後続の受信操作を大きなバッファーで使用してメッセージ全体を取得できます。 それ以外の場合 (つまり、プロトコルは信頼性が低く、 MSG_PARTIALをサポートしていません)、余分なデータが失われ、 WSARecvFrom によってエラー WSAEMSGSIZE が生成されます。

lpFlags パラメーターを使用すると、関連付けられたソケットに指定されたオプションを超えて、関数呼び出しの動作に影響を与えることができます。 つまり、この関数のセマンティクスは、ソケット オプションと lpFlags パラメーターによって決定されます。 後者は、次の表に示す値のいずれかと共に、ビットごとの OR 演算子を使用して構築されます。

説明
MSG_PEEK 受信データをプレビューします。 データはバッファーにコピーされますが、入力キューからは削除されません。 このフラグは、オーバーラップされていないソケットに対してのみ有効です。
MSG_OOB OOB データを処理します。
MSG_PARTIAL このフラグは、メッセージ指向ソケット専用です。 出力時に、このフラグは、データが送信者によって送信されるメッセージの一部であることを示します。 メッセージの残りの部分は、後続の受信操作で送信されます。 MSG_PARTIAL フラグがクリアされた後続の受信操作は、送信者のメッセージの末尾を示します。

入力パラメーターとして、このフラグは、サービス プロバイダーによってメッセージの一部のみが受信された場合でも、受信操作を完了する必要があることを示します。

 

メッセージ指向ソケットの場合、部分的なメッセージを受信した場合、lpFlags パラメーターにMSG_PARTIAL ビットが設定されます。 完全なメッセージを受信すると、lpFlagsMSG_PARTIALがクリアされます。 遅延完了の場合、 lpFlags が指す値は更新されません。 完了が示されたら、アプリケーションは WSAGetOverlappedResult を呼び出し、 lpdwFlags パラメーターによって指されるフラグを調べる必要があります。

メモlpOverlapped パラメーターを NULL に設定して WSARecvFrom などのブロッキング Winsock 呼び出しを発行する場合、Winsock は呼び出しを完了する前にネットワーク イベントを待機する必要がある場合があります。 Winsock は、この状況でアラート可能な待機を実行します。この待機は、同じスレッドでスケジュールされた非同期プロシージャ 呼び出し (APC) によって中断される可能性があります。 同じスレッドで進行中の Winsock 呼び出しを中断した APC 内で別のブロック Winsock 呼び出しを発行すると、未定義の動作が発生し、Winsock クライアントが試行してはなりません。
 

重複するソケット I/O

重複した操作がすぐに完了すると、 WSARecvFrom は 0 の値を返し、 lpNumberOfBytesRecvd パラメーターは受信したバイト数で更新され、 lpFlags パラメーターが指すフラグ ビットも更新されます。 重複した操作が正常に開始され、後で完了する場合、 WSARecvFromSOCKET_ERRORを 返し、エラー コード WSA_IO_PENDINGを示します。 この場合、 lpNumberOfBytesRecvdlpFlags は更新されません。 重複した操作が完了すると、転送されるデータの量は、完了ルーチンの cbTransferred パラメーター (指定されている場合) または WSAGetOverlappedResultlpcbTransfer パラメーターを使用して示されます。 フラグ値は、完了ルーチンの dwFlags パラメーターを使用するか、WSAGetOverlappedResultlpdwFlags パラメーターを調べることによって取得されます。

WSARecvFrom 関数は、前の WSARecv、WSARecvFromWSASend、または WSASendTo 関数の完了ルーチン内から呼び出すことができます。 特定のソケットの場合、I/O 完了ルーチンは入れ子になりません。 これにより、時間の影響を受けるデータ転送を、プリエンプティブ コンテキスト内で完全に実行できます。

lpOverlapped パラメーターは、重複する操作の間有効である必要があります。 複数の I/O 操作が同時に未処理の場合は、それぞれが個別の WSAOVERLAPPED 構造体を参照する必要があります。

lpCompletionRoutine パラメーターが NULL の場合、重複した操作が完了すると、lpOverlappedhEvent パラメーターに有効なイベント オブジェクト ハンドルが含まれている場合に通知されます。 アプリケーションでは 、WSAWaitForMultipleEvents または WSAGetOverlappedResult を使用して、イベント オブジェクトを待機またはポーリングできます。

lpCompletionRoutineNULL でない場合、hEvent パラメーターは無視され、アプリケーションがコンテキスト情報を完了ルーチンに渡すために使用できます。 NULL 以外の lpCompletionRoutine を渡し、同じ重複した I/O 要求に対して WSAGetOverlappedResult を呼び出す呼び出し元は、WSAGetOverlappedResult の呼び出しに対して fWait パラメーターを TRUE に設定できません。 この場合、 hEvent パラメーターの使用は未定義であり、 hEvent パラメーターを待機しようとすると予測できない結果が生成されます。

完了ルーチンは、Windows ファイル I/O 完了ルーチンに規定されているのと同じ規則に従います。 fAlertable パラメーターが TRUE に設定された関数 WSAWaitForMultipleEvents が呼び出されたときに、スレッドがアラート可能な待機状態になるまで、完了ルーチンは呼び出されません。

IO 完了ポートが使用され、 lpCompletionRoutine パラメーターと hEvent パラメーターが NULL の場合、操作の結果は IO 完了ポートでスケジュールされます。 これは、操作がすぐに完了するかどうかに関係なく、成功したすべての操作に対して発生します。

トランスポート プロバイダーを使用すると、アプリケーションはソケット I/O 完了ルーチンのコンテキスト内から送受信操作を呼び出し、特定のソケットに対して I/O 完了ルーチンが入れ子になることが保証されます。 これにより、時間の影響を受けるデータ転送を、プリエンプティブ コンテキスト内で完全に実行できます。

完了ルーチンのプロトタイプは次のとおりです。


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のリターン コードで満たされる前に、すべての待機完了ルーチンが呼び出されます。 完了ルーチンは任意の順序で呼び出すことができます。重複する操作が完了した順序は必ずしも同じではありません。 ただし、ポストされたバッファーは、指定した順序で入力することが保証されます。

コード例

次の例では、 WSARecvFrom 関数の使用方法を示します。
#ifndef UNICODE
#define UNICODE
#endif

#define WIN32_LEAN_AND_MEAN

#include <winsock2.h>
#include <Ws2tcpip.h>
#include <stdio.h>

int __cdecl main()
{

    WSADATA wsaData;
    WSABUF DataBuf;
    WSAOVERLAPPED Overlapped;

    SOCKET RecvSocket = INVALID_SOCKET;
    struct sockaddr_in RecvAddr;
    struct sockaddr_in SenderAddr;

    int SenderAddrSize = sizeof (SenderAddr);
    u_short Port = 27015;

    char RecvBuf[1024];
    int BufLen = 1024;
    DWORD BytesRecv = 0;
    DWORD Flags = 0;

    int err = 0;
    int rc;
    int retval = 0;
    
    //-----------------------------------------------
    // Initialize Winsock
    rc = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (rc != 0) {
        /* Could not find a usable Winsock DLL */
        wprintf(L"WSAStartup failed with error: %ld\n", rc);
        return 1;
    }

    // Make sure the Overlapped struct is zeroed out
    SecureZeroMemory((PVOID) &Overlapped, sizeof(WSAOVERLAPPED) );

    // Create an event handle and setup the overlapped structure.
    Overlapped.hEvent = WSACreateEvent();
    if (Overlapped.hEvent == NULL) {
        wprintf(L"WSACreateEvent failed with error: %d\n", WSAGetLastError());
        WSACleanup();
        return 1;
    }
    //-----------------------------------------------
    // Create a receiver socket to receive datagrams
    RecvSocket = WSASocket(AF_INET,
                           SOCK_DGRAM,
                           IPPROTO_UDP, NULL, 0, WSA_FLAG_OVERLAPPED);

    if (RecvSocket == INVALID_SOCKET) {
        /* Could not open a socket */
        wprintf(L"WSASocket failed with error: %ld\n", WSAGetLastError());
        WSACloseEvent(Overlapped.hEvent);
        WSACleanup();
        return 1;
    }
    //-----------------------------------------------
    // Bind the socket to any address and the specified port.
    RecvAddr.sin_family = AF_INET;
    RecvAddr.sin_port = htons(Port);
    RecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);

    rc = bind(RecvSocket, (SOCKADDR *) & RecvAddr, sizeof (RecvAddr));
    if (rc != 0) {
        /* Bind to the socket failed */
        wprintf(L"bind failed with error: %ld\n", WSAGetLastError());
        WSACloseEvent(Overlapped.hEvent);
        closesocket(RecvSocket);
        WSACleanup();
        return 1;
    }

    //-----------------------------------------------
    // Call the recvfrom function to receive datagrams
    // on the bound socket.
    DataBuf.len = BufLen;
    DataBuf.buf = RecvBuf;
    wprintf(L"Listening for incoming datagrams on port=%d\n", Port);
    rc = WSARecvFrom(RecvSocket,
                      &DataBuf,
                      1,
                      &BytesRecv,
                      &Flags,
                      (SOCKADDR *) & SenderAddr,
                      &SenderAddrSize, &Overlapped, NULL);

    if (rc != 0) {
        err = WSAGetLastError();
        if (err != WSA_IO_PENDING) {
            wprintf(L"WSARecvFrom failed with error: %ld\n", err);
            WSACloseEvent(Overlapped.hEvent);
            closesocket(RecvSocket);
            WSACleanup();
            return 1;
        }
        else {
            rc = WSAWaitForMultipleEvents(1, &Overlapped.hEvent, TRUE, INFINITE, TRUE);
            if (rc == WSA_WAIT_FAILED) {
                wprintf(L"WSAWaitForMultipleEvents failed with error: %d\n", WSAGetLastError());
                retval = 1;
            }

            rc = WSAGetOverlappedResult(RecvSocket, &Overlapped, &BytesRecv,
                                FALSE, &Flags);
            if (rc == FALSE) {
                wprintf(L"WSArecvFrom failed with error: %d\n", WSAGetLastError());
                retval = 1;
            }
            else
                wprintf(L"Number of received bytes = %d\n", BytesRecv);
                
            wprintf(L"Finished receiving. Closing socket.\n");
        }
        
    }
    //---------------------------------------------
    // When the application is finished receiving, close the socket.

    WSACloseEvent(Overlapped.hEvent);
    closesocket(RecvSocket);
    wprintf(L"Exiting.\n");

    //---------------------------------------------
    // Clean up and quit.
    WSACleanup();
    return (retval);
}

Windows Phone 8: この関数は、Windows Phone 8 以降の Windows Phone ストア アプリでサポートされています。

Windows 8.1Windows 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

関連項目

Wsabuf

WSACloseEvent

WSACreateEvent

WSAGetOverlappedResult

WSAOVERLAPPED

WSASend

WSASendTo

WSASocket

WSAWaitForMultipleEvents

Winsock 関数

Winsock リファレンス

Sendto