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 は、重複した操作が正常に開始され、その完了が後で示されることを示します。 その他のエラー コードは、重複した操作が正常に開始されず、完了の兆候が発生しないことを示します。
エラー コード | 意味 |
---|---|
要求されたアドレスはブロードキャスト アドレスですが、適切なフラグが設定されていません。 | |
リモート アドレスが有効なアドレス (ADDR_ANY など) ではありません。 | |
指定されたファミリーのアドレスをこのソケットと共に使用することはできません。 | |
UDP データグラム ソケットの場合、このエラーは、以前の送信操作で ICMP "ポートに到達できません" メッセージが発生したことを示します。 | |
宛先アドレスが必要です。 | |
lpBuffers、lpTo、lpOverlapped、lpNumberOfBytesSent、または lpCompletionRoutine パラメーターがユーザー アドレス空間に含まれていないか、lpTo パラメーターが小さすぎます。 | |
到達できないホストに対してソケット操作を実行しようとしました。 | |
ブロックしている Windows Sockets 1.1 呼び出しが進行中であるか、サービス プロバイダーがコールバック関数を処理しています。 | |
WSACancelBlockingCall を使用して、Windows Socket 1.1 の呼び出しをブロックしているが取り消されました。 | |
ソケットが バインドされていないか、またはソケットが重複フラグで作成されていません。 | |
ソケットはメッセージ指向であり、メッセージは基になるトランスポートでサポートされる最大値を超えています。 | |
ネットワーク サブシステムが失敗しました。 | |
データグラム ソケットに関して、このエラーは有効期限が切れたことを示します。 | |
現在このホストからネットワークには到達できません。 | |
Windows ソケット プロバイダーは、バッファー のデッドロックを報告します。 | |
ソケットが接続されていません (接続指向のソケットのみ)。 | |
記述子はソケットではありません。 | |
ソケットがシャットダウンされました。SD_SENDまたはSD_BOTHに設定された方法でシャットダウンが呼び出された後、ソケットで WSASendTo を実行することはできません。 | |
Windows NT:
重複するソケット: 未解決の重複した I/O 要求が多すぎます。 オーバーラップされていないソケット: ソケットは非ブロッキングとしてマークされ、送信操作をすぐに完了することはできません。 |
|
この関数を使用する前に、 WSAStartup 呼び出しが正常に行われる必要があります。 | |
重複した操作が正常に開始され、完了は後で示されます。 | |
ソケットのクローズ、または WSAIoctl での SIO_FLUSH コマンドの実行により、重複した操作が取り消されました。 |
注釈
WSASendTo 関数は、次の 2 つの重要な領域で、標準の sendto 関数よりも強化された機能を提供します。
- 重複するソケットと組み合わせて使用して、重複する送信操作を実行できます。
- これにより、複数の送信バッファーを指定できるため、I/O の分散/収集タイプに適用できます。
重複するソケット (フラグ WSA_FLAG_OVERLAPPEDを使用して WSASocket を使用して作成) の場合、lpOverlapped と lpCompletionRoutine の両方が NULL でない限り、データ送信では重複した I/O が使用されます。この場合、ソケットはオーバーラップされていないソケットとして扱われます。 バッファーがトランスポートによって使用されると、完了表示 (完了ルーチンの呼び出しまたはイベント オブジェクトの設定) が発生します。 操作がすぐに完了しない場合は、完了ルーチンまたは WSAGetOverlappedResult を使用して最終的な完了状態が取得されます。
オーバーラップされていないソケットの場合、最後の 2 つのパラメーター (lpOverlapped、 lpCompletionRoutine) は無視され、 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 は、部分的なメッセージ転送をサポートしていないトランスポートによって返されることに注意してください。 |
重複するソケット I/O
重複した操作がすぐに完了すると、 WSASendTo は 0 の値を返し、 lpNumberOfBytesSent パラメーターは送信されたバイト数で更新されます。 重複した操作が正常に開始され、後で完了する場合、 WSASendTo は SOCKET_ERRORを 返し、エラー コード WSA_IO_PENDINGを示します。 この場合、 lpNumberOfBytesSent は更新されません。 重複した操作が完了すると、転送されるデータの量は、完了ルーチンの cbTransferred パラメーター (指定されている場合) または WSAGetOverlappedResult の lpcbTransfer パラメーターを使用して示されます。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 が呼び出されたときに、スレッドがアラート可能な待機状態になるまで、完了ルーチンは呼び出されません。
トランスポート プロバイダーを使用すると、アプリケーションはソケット 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.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 |