WSASend 函式 (winsock2.h)
WSASend 函式會在連接的套接字上傳送數據。
語法
int WSAAPI WSASend(
[in] SOCKET s,
[in] LPWSABUF lpBuffers,
[in] DWORD dwBufferCount,
[out] LPDWORD lpNumberOfBytesSent,
[in] DWORD dwFlags,
[in] LPWSAOVERLAPPED lpOverlapped,
[in] LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);
參數
[in] s
識別已連線套接字的描述項。
[in] lpBuffers
WSABUF 結構的陣列指標。 每個 WSABUF 結構都包含緩衝區的指標,以及緩衝區的長度,以位元組為單位。 針對 Winsock 應用程式,一旦呼叫 WSASend 函式,系統就會擁有這些緩衝區,而且應用程式可能無法存取它們。 此陣列在傳送作業期間必須保持有效。
[in] dwBufferCount
lpBuffers 陣列中的 WSABUF 結構數目。
[out] lpNumberOfBytesSent
如果 I/O 作業立即完成,則此呼叫所傳送之數位的指標,以位元組為單位。
如果 lpOverlapped 參數不是 NULL,請針對此參數使用 NULL,以避免發生錯誤的結果。 只有當 lpOverlapped 參數不是 NULL 時,此參數才能為 NULL。
[in] dwFlags
用來修改 WSASend 函式呼叫行為的旗標。 如需詳細資訊,請參閱一節中的使用 dwFlags 。
[in] lpOverlapped
WSAOVERLAPPED 結構的指標。 非重迭套接字會忽略此參數。
[in] lpCompletionRoutine
類型:_In_opt_ LPWSAOVERLAPPED_COMPLETION_ROUTINE
完成作業完成時呼叫之完成例程的指標。 非重迭套接字會忽略此參數。
傳回值
如果沒有發生錯誤,而且傳送作業已立即完成, WSASend 會傳回零。 在此情況下,一旦呼叫線程處於可警示狀態,就會排程完成例程來呼叫。 否則,會傳回 SOCKET_ERROR 的值,而且可以呼叫 WSAGetLastError 來擷取特定的錯誤碼。 錯誤碼 WSA_IO_PENDING 指出重疊的作業已成功起始,且稍後將會指出完成。 任何其他錯誤碼都表示重疊的作業未成功起始,而且不會發生任何完成指示。
錯誤碼 | 意義 |
---|---|
此虛擬電路由於逾時或其他錯誤而終止。 | |
針對數據流套接字,虛擬線路已由遠端重設。 此通訊端無法再使用,應用程式應予以關閉。 針對 UDP 數據報套接字,此錯誤會指出先前的傳送作業導致 ICMP「無法連線埠」訊息。 | |
lpBuffers、lpNumberOfBytesSent、lpOverlapped、lpCompletionRoutine 參數並未完全包含在使用者地址空間的有效部分。 | |
封鎖的 Windows Socket 1.1 呼叫已透過 WSACancelBlockingCall 取消。 | |
封鎖的 Windows Sockets 1.1 呼叫正在進行中,或者服務提供者仍在處理回呼函式。 | |
套接字尚未與 系結系結 ,或未使用重迭旗標建立套接字。 | |
套接字是訊息導向,而且訊息大於基礎傳輸所支援的最大數目。 | |
網路子系統失敗。 | |
對於數據流套接字,連線已中斷,因為持續活動偵測到作業進行時發生失敗。 如果是資料包通訊端,此錯誤表示已超過存留時間。 | |
Windows Sockets 提供者會報告緩衝區死結。 | |
未連接此通訊端。 | |
描述項不是套接字。 | |
已指定MSG_OOB ,但套接字不是數據流樣式,例如類型 SOCK_STREAM、與此套接字相關聯的通訊網域不支援 OOB 數據、 不支援MSG_PARTIAL ,或套接字是單向的,而且只支援接收作業。 | |
套接字已關閉;在叫用關閉后,無法在套接字上呼叫 WSASend,以及如何設定為SD_SEND或SD_BOTH。 | |
Windows NT:
重疊的套接字:有太多未處理的重疊 I/O 要求。 未重疊的套接字:套接字標示為非封鎖,且無法立即完成傳送作業。 |
|
使用此函式之前,必須先進行成功的 WSAStartup 呼叫。 | |
已成功起始重疊的作業,稍後將會指出完成。 | |
由於套接字關閉、 WSAIoctl 中的 「SIO_FLUSH」 命令執行,或起始重疊要求的線程在作業完成之前結束,所以已取消重疊的作業。 如需詳細資訊,請參閱<備註>一節。 |
備註
WSASend 函式在兩個重要區域中提供標準傳送函式的功能以上:
WSASend 函式可用來從 s 所指定的連接導向套接字上,從一或多個緩衝區寫入傳出數據。 不過,它也可以在透過 連線 或 WSAConnect 函式建立的預設對等地址的無連線套接字上使用。套接字函式所建立的 套接字 將具有重疊屬性做為預設值。 WSASocket 函式所建立的套接字,具有傳遞至具有WSA_FLAG_OVERLAPPED位集之 WSASocket 的 dwFlags 參數將會有重疊的屬性。 對於具有重疊屬性的套接字,除非 lpOverlapped 和 lpCompletionRoutine 參數都是 NULL,否則 WSASend 會使用重疊的 I/O。 在此情況下,套接字會被視為非重疊的套接字。 當傳輸已取用緩衝區 () 時,就會發生完成指示,叫用事件物件的例程或設定。 如果作業未立即完成,則會透過完成例程或 WSAGetOverlappedResult 擷取最終完成狀態。
如果 lpOverlapped 和 lpCompletionRoutine 都是 NULL,此函式中的套接字將會被視為非重疊的套接字。
對於非重疊的套接字,會忽略最後兩個參數 (lpOverlapped、 lpCompletionRoutine) ,而 WSASend 採用與 傳送相同的封鎖語意。 數據會從緩衝區 () 複製到傳輸的緩衝區。 如果套接字不是封鎖和數據流導向,而且傳輸緩衝區中沒有足夠的空間, WSASend 只會傳回應用程式緩衝區的一部分。 假設相同的緩衝區情況和封鎖套接字, WSASend 將會封鎖,直到所有應用程式緩衝區內容都已取用為止。
對於訊息導向套接字,請勿超過基礎提供者的訊息大小上限,可藉由取得套接字選項的值 SO_MAX_MSG_SIZE來取得。 如果數據太長而無法透過基礎通訊協議傳遞,則會傳回 WSAEMSGSIZE 錯誤,而且不會傳輸任何數據。
Windows Me/98/95: WSASend 函式不支持超過16個緩衝區。
使用 dwFlags
dwFlags 參數可用來影響函式調用的行為,而超出針對相關聯套接字指定的選項。 也就是說,此函式的語意取決於套接字選項和 dwFlags 參數。 後者是使用位 OR 運算元搭配下表所列的任何值來建構。值 | 意義 |
---|---|
MSG_DONTROUTE | 指定數據不應受限於路由。 Windows Sockets 服務提供者可以選擇忽略此旗標。 |
MSG_OOB | 只在數據流樣式套接字上傳送 OOB 數據,例如 SOCK_STREAM 。 |
MSG_PARTIAL | 指定 lpBuffers 只包含部分訊息。 請注意,不支援部分訊息傳輸的傳輸會傳回錯誤碼 WSAEOPNOTSUPP 。 |
重疊的套接字 I/O
如果重疊的作業立即完成, WSASend 會傳回值為零,且 lpNumberOfBytesSent 參數會以傳送的位元元組數目來更新。 如果重疊的作業已成功起始,且稍後會完成, WSASend 會傳回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 完成例程不會巢狀。 這可讓時間敏感的數據傳輸完全發生在先佔式內容內。
下列 C++ 程式代碼範例是完成例程的原型。
void CALLBACK CompletionROUTINE(
IN DWORD dwError,
IN DWORD cbTransferred,
IN LPWSAOVERLAPPED lpOverlapped,
IN DWORD dwFlags
);
CompletionRoutine 函式是應用程式定義或連結庫定義函數名稱的佔位元。 dwError 參數會指定重迭作業的完成狀態,如 lpOverlapped 所指出。 cbTransferred 會指定傳送的位元元組數目。 目前沒有定義旗標值, dwFlags 將會是零。 此函式不會傳回值。
從此函式傳回允許叫用此套接字的另一個擱置完成例程。 所有等候完成例程都會在可警示線程的等候符合 WSA_IO_COMPLETION的傳回碼之前呼叫。 您可以依任何順序呼叫完成例程,不一定以相同順序呼叫重疊作業。 不過,保證會以指定的相同順序傳送張貼的緩衝區。
對 WSASend 進行的呼叫順序也是緩衝區傳輸至傳輸層的順序。 WSASend 不應該同時從不同的線程在相同的數據流導向套接字上呼叫,因為某些 Winsock 提供者可能會將大型傳送要求分割成多個傳輸,這可能會導致來自相同數據流導向套接字上多個並行傳送要求的非預期數據交錯。
範例程序代碼
下列程式代碼範例示範如何在重疊的 I/O 模式中使用 WSASend 函式。#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")
#define DATA_BUFSIZE 4096
#define SEND_COUNT 10
int __cdecl main()
{
WSADATA wsd;
struct addrinfo *result = NULL;
struct addrinfo hints;
WSAOVERLAPPED SendOverlapped;
SOCKET ListenSocket = INVALID_SOCKET;
SOCKET AcceptSocket = INVALID_SOCKET;
WSABUF DataBuf;
DWORD SendBytes;
DWORD Flags;
char buffer[DATA_BUFSIZE];
int err = 0;
int rc, i;
// Load Winsock
rc = WSAStartup(MAKEWORD(2, 2), &wsd);
if (rc != 0) {
printf("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 obtain the
// wildcard bind address for IPv4
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
rc = getaddrinfo(NULL, "27015", &hints, &result);
if (rc != 0) {
printf("getaddrinfo failed with error: %d\n", rc);
return 1;
}
ListenSocket = socket(result->ai_family,
result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET) {
printf("socket failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
return 1;
}
rc = bind(ListenSocket, result->ai_addr, (int) result->ai_addrlen);
if (rc == SOCKET_ERROR) {
printf("bind failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
return 1;
}
rc = listen(ListenSocket, 1);
if (rc == SOCKET_ERROR) {
printf("listen failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
return 1;
}
// Accept an incoming connection request
AcceptSocket = accept(ListenSocket, NULL, NULL);
if (AcceptSocket == INVALID_SOCKET) {
printf("accept failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
return 1;
}
printf("Client Accepted...\n");
// Make sure the SendOverlapped struct is zeroed out
SecureZeroMemory((PVOID) & SendOverlapped, sizeof (WSAOVERLAPPED));
// Create an event handle and setup the overlapped structure.
SendOverlapped.hEvent = WSACreateEvent();
if (SendOverlapped.hEvent == NULL) {
printf("WSACreateEvent failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
closesocket(AcceptSocket);
return 1;
}
DataBuf.len = DATA_BUFSIZE;
DataBuf.buf = buffer;
for (i = 0; i < SEND_COUNT; i++) {
rc = WSASend(AcceptSocket, &DataBuf, 1,
&SendBytes, 0, &SendOverlapped, NULL);
if ((rc == SOCKET_ERROR) &&
(WSA_IO_PENDING != (err = WSAGetLastError()))) {
printf("WSASend failed with error: %d\n", err);
break;
}
rc = WSAWaitForMultipleEvents(1, &SendOverlapped.hEvent, TRUE, INFINITE,
TRUE);
if (rc == WSA_WAIT_FAILED) {
printf("WSAWaitForMultipleEvents failed with error: %d\n",
WSAGetLastError());
break;
}
rc = WSAGetOverlappedResult(AcceptSocket, &SendOverlapped, &SendBytes,
FALSE, &Flags);
if (rc == FALSE) {
printf("WSASend failed with error: %d\n", WSAGetLastError());
break;
}
printf("Wrote %d bytes\n", SendBytes);
WSAResetEvent(SendOverlapped.hEvent);
}
WSACloseEvent(SendOverlapped.hEvent);
closesocket(AcceptSocket);
closesocket(ListenSocket);
freeaddrinfo(result);
WSACleanup();
return 0;
}
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 |