WSASendTo 関数 (winsock2.h)

WSASendTo 関数は、該当する場合は重複した I/O を使用して、特定の宛先にデータを送信します。

構文

int WSAAPI WSASendTo(
  [in]  SOCKET                             s,
  [in]  LPWSABUF                           lpBuffers,
  [in]  DWORD                              dwBufferCount,
  [out] LPDWORD                            lpNumberOfBytesSent,
  [in]  DWORD                              dwFlags,
  [in]  const sockaddr                     *lpTo,
  [in]  int                                iTolen,
  [in]  LPWSAOVERLAPPED                    lpOverlapped,
  [in]  LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);

パラメーター

[in] s

(接続されている可能性がある) ソケットを識別する記述子。

[in] lpBuffers

WSABUF 構造体の配列へのポインター。 各 WSABUF 構造体には、バッファーへのポインターとバッファーの長さ (バイト単位) が含まれます。 Winsock アプリケーションの場合、 WSASendTo 関数が呼び出されると、システムはこれらのバッファーを所有し、アプリケーションがそれらにアクセスできない可能性があります。 この配列は、送信操作の間有効なままである必要があります。

[in] dwBufferCount

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

[out] lpNumberOfBytesSent

I/O 操作が直ちに完了した場合に、この呼び出しによって送信されたバイト数へのポインター。

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

[in] dwFlags

WSASendTo 関数呼び出しの動作を変更するために使用されるフラグ。

[in] lpTo

SOCKADDR 構造体内のターゲット ソケットのアドレスへのオプションのポインター。

[in] iTolen

lpTo パラメーターのアドレスのサイズ (バイト単位)。

[in] lpOverlapped

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

[in] lpCompletionRoutine

種類: _In_opt_ LPWSAOVERLAPPED_COMPLETION_ROUTINE

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

戻り値

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

エラー コード 意味
WSAEACCES
要求されたアドレスはブロードキャスト アドレスですが、適切なフラグが設定されていません。
WSAEADDRNOTAVAIL
リモート アドレスが有効なアドレス (ADDR_ANY など) ではありません。
WSAEAFNOSUPPORT
指定されたファミリーのアドレスをこのソケットと共に使用することはできません。
WSAECONNRESET
UDP データグラム ソケットの場合、このエラーは、以前の送信操作で ICMP "ポートに到達できません" メッセージが発生したことを示します。
WSAEDESTADDRREQ
宛先アドレスが必要です。
WSAEFAULT
lpBufferslpTolpOverlappedlpNumberOfBytesSent、または lpCompletionRoutine パラメーターがユーザー アドレス空間に含まれていないか、lpTo パラメーターが小さすぎます。
WSAEHOSTUNREACH
到達できないホストに対してソケット操作を実行しようとしました。
WSAEINPROGRESS
ブロックしている Windows Sockets 1.1 呼び出しが進行中であるか、サービス プロバイダーがコールバック関数を処理しています。
WSAEINTR
WSACancelBlockingCall を使用して、Windows Socket 1.1 の呼び出しをブロックしているが取り消されました。
WSAEINVAL
ソケットが バインドされていないか、またはソケットが重複フラグで作成されていません。
WSAEMSGSIZE
ソケットはメッセージ指向であり、メッセージは基になるトランスポートでサポートされる最大値を超えています。
WSAENETDOWN
ネットワーク サブシステムが失敗しました。
WSAENETRESET
データグラム ソケットに関して、このエラーは有効期限が切れたことを示します。
WSAENETUNREACH
現在このホストからネットワークには到達できません。
WSAENOBUFS
Windows ソケット プロバイダーは、バッファー のデッドロックを報告します。
WSAENOTCONN
ソケットが接続されていません (接続指向のソケットのみ)。
WSAENOTSOCK
記述子はソケットではありません。
WSAESHUTDOWN
ソケットがシャットダウンされました。SD_SENDまたはSD_BOTHに設定された方法シャットダウンが呼び出された後、ソケットで WSASendTo を実行することはできません。
WSAEWOULDBLOCK
Windows NT:

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

WSANOTINITIALIZED
この関数を使用する前に、 WSAStartup 呼び出しが正常に行われる必要があります。
WSA_IO_PENDING
重複した操作が正常に開始され、完了は後で示されます。
WSA_OPERATION_ABORTED
ソケットのクローズ、または WSAIoctl での SIO_FLUSH コマンドの実行により、重複した操作が取り消されました。

注釈

WSASendTo 関数は、次の 2 つの重要な領域で、標準の sendto 関数よりも強化された機能を提供します。

  • 重複するソケットと組み合わせて使用して、重複する送信操作を実行できます。
  • これにより、複数の送信バッファーを指定できるため、I/O の分散/収集タイプに適用できます。
WSASendTo 関数は通常、lpToパラメーターで識別される特定のピア ソケットに 1 つ以上のバッファーに含まれるデータグラムを送信するために、 によって指定されたコネクションレス ソケットで使用されます。 接続なしのソケットが以前に connect 関数を使用して特定のアドレスに接続されていた場合でも、 lpTo はその特定のデータグラムの宛先アドレスのみをオーバーライドします。 接続指向ソケットでは、 lpTo パラメーターと iToLen パラメーターは無視されます。この場合、 WSASendToWSASend と同じです。

重複するソケット (フラグ WSA_FLAG_OVERLAPPEDを使用して WSASocket を使用して作成) の場合、lpOverlappedlpCompletionRoutine の両方が NULL でない限り、データ送信では重複した I/O が使用されます。この場合、ソケットはオーバーラップされていないソケットとして扱われます。 バッファーがトランスポートによって使用されると、完了表示 (完了ルーチンの呼び出しまたはイベント オブジェクトの設定) が発生します。 操作がすぐに完了しない場合は、完了ルーチンまたは WSAGetOverlappedResult を使用して最終的な完了状態が取得されます。

メモ ソケットが開かれた場合、 setsockopt 呼び出しが行われ、 sendto 呼び出しが行われると、Windows ソケットは暗黙的な バインド 関数呼び出しを実行します。
 
lpOverlappedlpCompletionRoutine の両方が NULL の場合、この関数のソケットは、オーバーラップされていないソケットとして扱われます。

オーバーラップされていないソケットの場合、最後の 2 つのパラメーター (lpOverlappedlpCompletionRoutine) は無視され、 WSASendTo はsend と同じブロック セマンティクスを採用します。 データはバッファーからトランスポート バッファーにコピーされます。 ソケットが非ブロッキングでストリーム指向で、トランスポートのバッファーに十分な領域がない場合、 WSASendTo は アプリケーションのバッファーの一部のみを使用して を返します。 同じバッファー状況とブロッキング ソケットが指定されると、 WSASendTo は、アプリケーションのすべてのバッファー コンテンツが使用されるまでブロックします。

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

メッセージ指向ソケットの場合は、基になるトランスポートの最大メッセージ サイズを超えないように注意する必要があります。これは、ソケット オプション SO_MAX_MSG_SIZEの値を取得することで取得できます。 データが長すぎて、基になるプロトコルをアトミックに通過できない場合は、 エラー WSAEMSGSIZE が返され、データは送信されません。

ソケットがバインドされていない場合は、システムによって一意の値がローカル関連付けに割り当てられ、ソケットはバインド済みとしてマークされます。

ソケットが接続されている場合は、 getsockname 関数を使用して、ソケットに関連付けられているローカル IP アドレスとポートを決定できます。

ソケットが接続されていない場合は、
getsockname 関数を使用してソケットに関連付けられているローカル ポート番号を確認できますが、返される IP アドレスは、指定されたプロトコルのワイルドカード アドレスに設定されます (たとえば、IPv4 の場合は INADDR_ANY または "0.0.0.0"、IPv6 の IN6ADDR_ANY_INIT場合は "::" です)。

WSASendTo が正常に完了しても、データが正常に配信されたことを示すものではありません。

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

意味
MSG_DONTROUTE データをルーティングの対象にしないことを指定します。 Windows ソケット サービス プロバイダーは、このフラグを無視することを選択できます。
MSG_OOB OOB データを送信する ( SOCK_STREAM などのストリーム スタイルのソケットのみ)。
MSG_PARTIAL lpBuffers に部分的なメッセージのみが含まれていることを指定します。 エラー コード WSAEOPNOTSUPP は、部分的なメッセージ転送をサポートしていないトランスポートによって返されることに注意してください。
 
メモlpOverlapped パラメーターを NULL に設定して WSASendTo などのブロッキング Winsock 呼び出しを発行する場合、Winsock は呼び出しを完了する前にネットワーク イベントを待機する必要がある場合があります。 Winsock は、この状況でアラート可能な待機を実行します。この待機は、同じスレッドでスケジュールされた非同期プロシージャ 呼び出し (APC) によって中断される可能性があります。 同じスレッドで進行中の Winsock 呼び出しを中断した APC 内で別のブロック Winsock 呼び出しを発行すると、未定義の動作が発生し、Winsock クライアントが試行してはなりません。
 

重複するソケット I/O

重複した操作がすぐに完了すると、 WSASendTo は 0 の値を返し、 lpNumberOfBytesSent パラメーターは送信されたバイト数で更新されます。 重複した操作が正常に開始され、後で完了する場合、 WSASendToSOCKET_ERRORを 返し、エラー コード WSA_IO_PENDINGを示します。 この場合、 lpNumberOfBytesSent は更新されません。 重複した操作が完了すると、転送されるデータの量は、完了ルーチンの cbTransferred パラメーター (指定されている場合) または WSAGetOverlappedResultlpcbTransfer パラメーターを使用して示されます。
メモ 特定のスレッドによって開始されたすべての I/O は、そのスレッドが終了すると取り消されます。 重複するソケットの場合、保留中の非同期操作は、操作が完了する前にスレッドが閉じられた場合に失敗する可能性があります。 詳細については、「 ExitThread 」を参照してください。
 
重複した I/O を使用する WSASendTo 関数は、前の WSARecv、WSARecvFromWSASend、または WSASendTo 関数の完了ルーチン内から呼び出すことができます。 これにより、時間の影響を受けるデータ転送を、プリエンプティブ コンテキスト内で完全に実行できます。

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 が呼び出されたときに、スレッドがアラート可能な待機状態になるまで、完了ルーチンは呼び出されません。

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

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


void CALLBACK CompletionROUTINE(
  IN DWORD dwError,
  IN DWORD cbTransferred,
  IN LPWSAOVERLAPPED lpOverlapped,
  IN DWORD dwFlags
);

CompletionRoutine 関数は、アプリケーション定義またはライブラリ定義の関数名のプレースホルダーです。 dwError パラメーターは、lpOverlapped で示されているように、重複する操作の完了状態を指定します。 cbTransferred パラメーターは、送信されたバイト数を指定します。 現在、フラグ値は定義されておらず、 dwFlags は 0 になります。 この関数は値を返しません。

この関数から戻って、このソケットに対して別の保留中の完了ルーチンを呼び出すことができます。 警告可能なスレッドの待機がWSA_IO_COMPLETIONの戻りコードで満たされる前に、すべての待機完了ルーチンが呼び出されます。 完了ルーチンは任意の順序で呼び出すことができます。重複する操作が完了した順序と同じ順序であるとは限りません。 ただし、ポストされたバッファーは、指定した順序で送信することが保証されます。

コード例

次の例では、イベント オブジェクトを使用して WSASendTo 関数を使用する方法を示します。
#define WIN32_LEAN_AND_MEAN

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

// Link with ws2_32.lib
#pragma comment(lib, "Ws2_32.lib")

int __cdecl main(int argc, char **argv)
{

    //---------------------------------------------
    // Declare and initialize variables
    WSADATA wsaData;
    WSABUF DataBuf;

    WSAOVERLAPPED Overlapped;
    SOCKET SendToSocket = INVALID_SOCKET;

    struct sockaddr_in RecvAddr;
    struct sockaddr_in LocalAddr;
    int RecvAddrSize = sizeof (RecvAddr);
    int LocalAddrSize = sizeof (LocalAddr);

    u_short Port = 27777;
    struct hostent *localHost;
    char *ip;
    
    char *targetip;
    char *targetport;

    char SendBuf[1024] = "Data buffer to send";
    int BufLen = 1024;
    DWORD BytesSent = 0;
    DWORD Flags = 0;

    int rc, err;
    int retval = 0;

    // Validate the parameters
    if (argc != 3) {
        printf("usage: %s targetip port\n", argv[0]);
        printf("  to sendto the localhost on port 27777\n");
        printf("       %s 127.0.0.1 27777\n", argv[0]);
        return 1;
    }

    targetip = argv[1];
    targetport = argv[2];

    //---------------------------------------------
    // Initialize Winsock
    // Load Winsock
    rc = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (rc != 0) {
        printf("Unable to load Winsock: %d\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 == WSA_INVALID_EVENT) {
        printf("WSACreateEvent failed with error: %d\n", WSAGetLastError());
        WSACleanup();
        return 1;
    }
    //---------------------------------------------
    // Create a socket for sending data
    SendToSocket =
        WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, 0,
                  WSA_FLAG_OVERLAPPED);
    if (SendToSocket == INVALID_SOCKET) {
        printf("socket failed with error: %d\n", WSAGetLastError());
        WSACloseEvent(Overlapped.hEvent);
        WSACleanup();
        return 1;
    }
    //---------------------------------------------
    // Set up the RecvAddr structure with the IP address of
    // the receiver (in this example case "123.123.123.1")
    // and the specified port number.
    RecvAddr.sin_family = AF_INET;

    RecvAddr.sin_addr.s_addr = inet_addr(targetip);
    if (RecvAddr.sin_addr.s_addr == INADDR_NONE)  {
        printf("The target ip address entered must be a legal IPv4 address\n");
        WSACloseEvent(Overlapped.hEvent);
        WSACleanup();
        return 1;
    }
    RecvAddr.sin_port = htons( (u_short) atoi(targetport));
    if(RecvAddr.sin_port == 0) {
        printf("The targetport must be a legal UDP port number\n");
        WSACloseEvent(Overlapped.hEvent);
        WSACleanup();
        return 1;
    }

    //---------------------------------------------
    // Set up the LocalAddr structure with the local IP address
    // and the specified port number.
    localHost = gethostbyname("");
    ip = inet_ntoa(*(struct in_addr *) *localHost->h_addr_list);

    LocalAddr.sin_family = AF_INET;
    LocalAddr.sin_addr.s_addr = inet_addr(ip);
    LocalAddr.sin_port = htons(Port);

    //---------------------------------------------
    // Bind the sending socket to the LocalAddr structure
    // that has the internet address family, local IP address
    // and specified port number.  
    rc = bind(SendToSocket, (struct sockaddr *) &LocalAddr, LocalAddrSize);
    if (rc == SOCKET_ERROR) {
        printf("bind failed with error: %d\n", WSAGetLastError());
        WSACloseEvent(Overlapped.hEvent);
        closesocket(SendToSocket);
        WSACleanup();
        return 1;
    }
    //---------------------------------------------
    // Send a datagram to the receiver
    printf("Sending datagram from IPv4 address = %s port=%d\n", 
       inet_ntoa(LocalAddr.sin_addr), ntohs(LocalAddr.sin_port) ); 
    printf("   to IPv4 address = %s port=%d\n", 
       inet_ntoa(RecvAddr.sin_addr), ntohs(RecvAddr.sin_port) ); 

//    printf("Sending a datagram...\n");
    DataBuf.len = BufLen;
    DataBuf.buf = SendBuf;
    rc = WSASendTo(SendToSocket, &DataBuf, 1,
                   &BytesSent, Flags, (SOCKADDR *) & RecvAddr,
                   RecvAddrSize, &Overlapped, NULL);

    if ((rc == SOCKET_ERROR) && (WSA_IO_PENDING != (err = WSAGetLastError()))) {
        printf("WSASendTo failed with error: %d\n", err);
        WSACloseEvent(Overlapped.hEvent);
        closesocket(SendToSocket);
        WSACleanup();
        return 1;
    }

    rc = WSAWaitForMultipleEvents(1, &Overlapped.hEvent, TRUE, INFINITE, TRUE);
    if (rc == WSA_WAIT_FAILED) {
        printf("WSAWaitForMultipleEvents failed with error: %d\n",
                WSAGetLastError());
        retval = 1;
    }

    rc = WSAGetOverlappedResult(SendToSocket, &Overlapped, &BytesSent,
                                FALSE, &Flags);
    if (rc == FALSE) {
        printf("WSASendTo failed with error: %d\n", WSAGetLastError());
        retval = 1;
    }
    else
        printf("Number of sent bytes = %d\n", BytesSent);
        
    //---------------------------------------------
    // When the application is finished sending, close the socket.
    printf("Finished sending. Closing socket.\n");
    WSACloseEvent(Overlapped.hEvent);
    closesocket(SendToSocket);
    printf("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

こちらもご覧ください

WSACloseEvent

WSACreateEvent

WSAGetOverlappedResult

WSASocket

WSAWaitForMultipleEvents

Winsock 関数

Winsock リファレンス