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 會 傳回零。 在此情況下,一旦呼叫線程處於可警示狀態,就會排程完成例程來呼叫。 否則,會傳回 SOCKET_ERROR 的值,而且可以呼叫 WSAGetLastError 來擷取特定的錯誤碼。 錯誤碼 WSA_IO_PENDING 指出重疊的作業已成功起始,且稍後將會指出完成。 任何其他錯誤碼都表示重疊的作業未成功起始,而且不會發生任何完成指示。
錯誤碼 | 意義 |
---|---|
要求的位址是廣播位址,但未設定適當的旗標。 | |
遠程位址不是有效的位址 (,例如 ADDR_ANY) 。 | |
指定之系列中的位址無法用於此通訊端。 | |
針對 UDP 數據報套接字,此錯誤會指出先前的傳送作業導致 ICMP「無法連線埠」訊息。 | |
需要目的地位址。 | |
lpBuffers、lpTo、lpOverlapped、lpNumberOfBytesSent 或 lpCompletionRoutine 參數不是使用者地址空間的一部分,或 lpTo 參數太小。 | |
已嘗試對無法連接的主機進行通訊端作業。 | |
封鎖的 Windows Sockets 1.1 呼叫正在進行中,或者服務提供者仍在處理回呼函式。 | |
封鎖的 Windows Socket 1.1 呼叫已透過 WSACancelBlockingCall 取消。 | |
套接字尚未與 系結系結,或未使用重迭旗標建立套接字。 | |
套接字是訊息導向,而且訊息大於基礎傳輸所支援的最大數目。 | |
網路子系統失敗。 | |
如果是資料包通訊端,此錯誤表示已超過存留時間。 | |
此時無法透過此主機連接網路。 | |
Windows Sockets 提供者會報告緩衝區死結。 | |
套接字未連線 (連線導向套接字) 。 | |
描述項不是套接字。 | |
套接字已關閉;在關閉之後,無法叫用套接字上的 WSASendTo,以及如何設定為 SD_SEND 或 SD_BOTH。 | |
Windows NT:
重疊的套接字:有太多未處理的重疊 I/O 要求。 未重疊的套接字:套接字標示為非封鎖,且無法立即完成傳送作業。 |
|
使用此函式之前,必須先進行成功的 WSAStartup 呼叫。 | |
已成功起始重疊的作業,稍後將會指出完成。 | |
因為套接字關閉,或 WSAIoctl 中執行SIO_FLUSH命令,所以已取消重疊的作業。 |
備註
WSASendTo 函式在兩個重要區域中,透過標準 sendto 函式提供增強的功能:
- 它可與重疊的套接字搭配使用,以執行重疊的傳送作業。
- 它允許指定多個傳送緩衝區,使其適用於 I/O 的散佈/收集類型。
對於使用 WSASocket 與旗標WSA_FLAG_OVERLAPPED建立的重疊套接字 (,) 傳送數據時,除非 lpOverlapped 和 lpCompletionRoutine 都是 NULL ,在此情況下,套接字會被視為未重疊的套接字。 當傳輸已取用緩衝區 () 時, (叫用事件) 物件的完成例程或事件對象的設定,就會發生完成指示。 如果作業未立即完成,則會透過完成例程或 WSAGetOverlappedResult 擷取最終完成狀態。
對於非重迭套接字,最後兩個參數 (lpOverlapped、 lpCompletionRoutine) 會被忽略,而 WSASendTo 採用與 傳送相同的封鎖語意。 數據會從緩衝區 () 複製到傳輸緩衝區。 如果套接字為非封鎖和數據流導向,且傳輸緩衝區中沒有足夠的空間, 則 WSASendTo 只會傳回應用程式緩衝區的一部分。 假設相同的緩衝區情況和封鎖套接字, WSASendTo 將會封鎖,直到取用所有應用程式的緩衝區內容為止。
如果此函式是以重疊的方式完成,在從這個呼叫傳回之前,Winsock 服務提供者必須負責擷取 WSABUF 結構。 這可讓應用程式建置 lpBuffers 參數所指向的堆疊型 WSABUF 陣列。
對於訊息導向套接字,請務必小心不要超過基礎傳輸的最大訊息大小,這可以藉由取得套接字選項的值 SO_MAX_MSG_SIZE來取得。 如果數據太長而無法透過基礎通訊協議傳遞,則會傳回 WSAEMSGSIZE 錯誤,而且不會傳輸任何數據。
如果套接字未系結,系統會將唯一值指派給本機關聯,然後套接字會標示為系結。
如果套接字已連線, 則取得ockname 函式可用來判斷與套接字相關聯的本機 IP 位址和埠。
如果套接字未連線,則為
getsockname 函式可用來判斷與套接字相關聯的本機埠號碼,但傳回的 IP 位址會設定為指定通訊協定的通配符位址 (,例如,IPv4 INADDR_ANY或 “0.0.0.0”,而 IPv6) IN6ADDR_ANY_INIT 或 “::”。
WSASendTo 成功完成並不表示已成功傳遞數據。
dwFlags 參數可用來影響函式調用的行為,而超出針對相關聯套接字指定的選項。 也就是說,此函式的語意取決於套接字選項和 dwFlags 參數。 後者是使用位 OR 運算元搭配下表所列的任何值來建構。
值 | 意義 |
---|---|
MSG_DONTROUTE | 指定數據不應受限於路由。 Windows Socket 服務提供者可以選擇忽略此旗標。 |
MSG_OOB | (數據流樣式套接字傳送 OOB 數據 ,例如只 SOCK_STREAM) 。 |
MSG_PARTIAL | 指定 lpBuffers 只包含部分訊息。 請注意,不支援部分訊息傳輸的傳輸會傳回錯誤碼 WSAEOPNOTSUPP 。 |
重疊的套接字 I/O
如果重疊的作業立即完成, WSASendTo 會 傳回零的值,且 lpNumberOfBytesSent 參數會以傳送的位元元組數目來更新。 如果重疊的作業已成功起始,且稍後將會完成, WSASendTo 會傳回 SOCKET_ERROR ,並指出錯誤碼 WSA_IO_PENDING。 在此情況下,不會更新 lpNumberOfBytesSent 。 當重疊的作業完成時,會透過完成例 (程中的 cbTransferred 參數來指出傳輸的數據量,如果指定) ,或透過 WSAGetOverlappedResult 中的 lxmlTransfer 參數,則表示。lpOverlapped 參數在重迭作業期間必須有效。 如果同時未完成多個 I/O 作業,每個作業都必須參考個別 的 WSAOVERLAPPED 結構。
如果 lpCompletionRoutine 參數為 NULL,當重疊的作業包含有效的事件物件句柄時,就會發出 lpOverlapped 的 hEvent 參數訊號。 應用程式可以使用 WSAWaitForMultipleEvents 或 WSAGetOverlappedResult 來等候或輪詢事件物件。
如果 lpCompletionRoutine 不是 NULL, 則會忽略 hEvent 參數,並可供應用程式用來將內容資訊傳遞至完成例程。 呼叫端,將非 NULLlpCompletionRoutine 和更新版本針對相同的重疊 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 將會是零。 此函式不會傳回值。
從此函式傳回允許叫用此套接字的另一個擱置完成例程。 所有等候完成例程都會在可警示線程的等候符合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 Store 應用程式支援此函式。
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 |
程式庫 | Ws2_32.lib |
Dll | Ws2_32.dll |