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 指出重迭的作業已成功起始,且稍後會指出完成。 任何其他錯誤碼都表示重迭的作業未成功起始,而且不會發生任何完成指示。

錯誤碼 意義
WSAECONNABORTED
此虛擬電路由於逾時或其他錯誤而終止。
WSAECONNRESET
針對資料流程通訊端,虛擬線路已由遠端重設。 此通訊端無法再使用,應用程式應予以關閉。 針對 UDP 資料包通訊端,此錯誤會指出先前的傳送作業導致 ICMP「無法連線的埠」訊息。
WSAEFAULT
lpBufferslpNumberOfBytesSentlpOverlappedlpCompletionRoutine參數未完全包含在使用者位址空間的有效部分中。
WSAEINTR
封鎖的 Windows Socket 1.1 呼叫已透過 WSACancelBlockingCall取消。
WSAEINPROGRESS
封鎖的 Windows Sockets 1.1 呼叫正在進行中,或服務提供者仍在處理回呼函式。
WSAEINVAL
通訊端尚未與 結系結,或未使用重迭旗標建立通訊端。
WSAEMSGSIZE
通訊端是訊息導向,而且訊息大於基礎傳輸所支援的最大值。
WSAENETDOWN
網路子系統失敗。
WSAENETRESET
針對串流通訊端,連線已因為持續運作活動偵測作業進行時失敗而中斷。 如果是資料包通訊端,此錯誤表示已超過存留時間。
WSAENOBUFS
Windows Sockets 提供者會報告緩衝區死結。
WSAENOTCONN
未連接此通訊端。
WSAENOTSOCK
描述項不是通訊端。
WSAEOPNOTSUPP
已指定MSG_OOB ,但通訊端不是資料流程樣式,例如類型 SOCK_STREAM、與此通訊端相關聯的通訊網域不支援 OOB 資料、 不支援MSG_PARTIAL ,或通訊端為單向且僅支援接收作業。
WSAESHUTDOWN
通訊端已關閉;在叫用關機之後,無法叫用通訊端上的WSASend如何設定為SD_SENDSD_BOTH
WSAEWOULDBLOCK
Windows NT:

重迭的通訊端:有太多未處理的重迭 I/O 要求。 未重迭的通訊端:通訊端標示為非封鎖,且無法立即完成傳送作業。

WSANOTINITIALISED
使用這個函式之前,必須先進行成功的 WSAStartup 呼叫。
WSA_IO_PENDING
已成功起始重迭的作業,且稍後將會指出完成。
WSA_OPERATION_ABORTED
由於通訊端關閉、 WSAIoctl中的 「SIO_FLUSH」 命令執行,或起始重迭要求的執行緒在作業完成之前結束,因此已取消重迭作業。 如需詳細資訊,請參閱<備註>一節。

備註

WSASend函式在兩個重要區域中,提供標準傳送函式的功能超過和更高:

  • 它可以與重迭的通訊端搭配使用,以執行重迭 的傳送 作業。
  • 它允許指定多個 傳送 緩衝區,使其適用于 I/O 的散佈/收集類型。
WSASend函式可用來從s所指定連接導向通訊端上的一或多個緩衝區寫入傳出資料。 不過,它也可用於透過 connectWSAConnect 函式所建立之預設對等位址的無連線通訊端。

通訊端函式所建立的 通訊端 將具有重迭屬性做為預設值。 WSASocket函式所建立的通訊端,其dwFlags參數會傳遞至具有WSA_FLAG_OVERLAPPED位集的WSASocket會有重迭的屬性。 對於具有重迭屬性的通訊端,除非lpOverlappedlpCompletionRoutine參數都是Null,否則WSASend會使用重迭的 I/O。 在此情況下,通訊端會被視為非重迭的通訊端。 當傳輸已取用緩衝區 () 時,就會發生完成指示,叫用事件物件的常式或設定。 如果作業未立即完成,則會透過完成常式或 WSAGetOverlappedResult擷取最終完成狀態。

如果 lpOverlappedlpCompletionRoutine 都是 Null,此函式中的通訊端將會被視為非重迭的通訊端。

對於非重迭通訊端,最後兩個參數 (lpOverlappedlpCompletionRoutine) 會被忽略,而 WSASend 會採用與 傳送相同的封鎖語意。 資料會從緩衝區 () 複製到傳輸的緩衝區。 如果通訊端非封鎖和資料流程導向,而且傳輸緩衝區中沒有足夠的空間, WSASend 只會傳回應用程式緩衝區的一部分。 假設有相同的緩衝區狀況和封鎖通訊端, WSASend 將會封鎖,直到取用所有應用程式緩衝區內容為止。

注意 通訊端選項 SO_RCVTIMEOSO_SNDTIMEO 僅適用于封鎖通訊端。
 
如果以重迭的方式完成此函式,Winsock 服務提供者必須負責擷取 WSABUF 結構,然後再從這個呼叫傳回。 這可讓應用程式建置由 lpBuffers參數指向的堆疊型WSABUF陣列。

對於訊息導向通訊端,請勿超過基礎提供者的訊息大小上限,其可藉由取得通訊端選項的值 SO_MAX_MSG_SIZE來取得。 如果資料太長而無法透過基礎通訊協定傳遞,則會傳回 WSAEMSGSIZE 錯誤,而且不會傳輸任何資料。

Windows Me/98/95:WSASend函式不支援超過 16 個緩衝區。

注意WSASend成功完成不會指出已成功傳遞資料。
 

使用 dwFlags

dwFlags參數可用來影響函式調用的行為,超出為相關聯通訊端指定的選項。 也就是說,此函式的語意取決於通訊端選項和 dwFlags 參數。 後者是使用位 OR 運算子搭配下表所列的任何值來建構。
意義
MSG_DONTROUTE 指定資料不應受限於路由。 Windows Sockets 服務提供者可以選擇忽略此旗標。
MSG_OOB 只在資料流程樣式通訊端上傳送 OOB 資料,例如 SOCK_STREAM
MSG_PARTIAL 指定 lpBuffers 只包含部分訊息。 請注意,不支援部分訊息傳輸的傳輸會傳回錯誤碼 WSAEOPNOTSUPP
 
注意 發出封鎖的 Winsock 呼叫時,例如 WSASend ,並將 lpOverlapped 參數設定為 Null 時,Winsock 可能需要等候網路事件,才能完成呼叫。 Winsock 會在這種情況中執行可警示的等候,而非同步程序呼叫 (APC) 排程在同一個執行緒上,可能會中斷。 在 APC 內發出另一個封鎖 Winsock 呼叫,中斷相同執行緒上持續封鎖 Winsock 呼叫會導致未定義的行為,而且永遠不會由 Winsock 用戶端嘗試。
 

重迭的通訊端 I/O

如果重迭的作業立即完成, WSASend 會傳回值為零,且 lpNumberOfBytesSent 參數會以傳送的位元組數目來更新。 如果重迭的作業已成功起始,且稍後會完成, WSASend 會傳回SOCKET_ERROR,並指出錯誤碼 WSA_IO_PENDING。 在此情況下,不會更新 lpNumberOfBytesSent 。 當重迭的作業完成時,會透過完成例 (程中的cbTransferred參數來指出傳輸的資料量,如果指定) ,或透過WSAGetOverlappedResult中的lxmlTransfer參數,則表示。
注意 當該執行緒結束時,由指定執行緒起始的所有 I/O 都會取消。 對於重迭的通訊端,如果執行緒在作業完成之前關閉執行緒,擱置的非同步作業可能會失敗。 如需詳細資訊,請參閱 ExitThread
 
使用重迭 I/O 的 WSASend 函式可以從先前 WSARecvWSARecvFromWSASendWSASendTo 函式的完成常式內呼叫。 這可讓時間敏感的資料傳輸完全發生在先占式內容內。

lpOverlapped參數在重迭作業期間必須有效。 如果同時未完成多個 I/O 作業,每個作業都必須參考個別 的 WSAOVERLAPPED 結構。

如果lpCompletionRoutine參數為Null,當重迭的作業包含有效的事件物件控制碼時,就會發出 lpOverlappedhEvent參數訊號。 應用程式可以使用 WSAWaitForMultipleEventsWSAGetOverlappedResult 來等候或輪詢事件物件。

如果 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市集應用程式支援此函式。

Windows 8.1Windows Server 2012 R2:Windows 市集應用程式支援此功能,Windows 8.1、Windows Server 2012 R2 及更新版本。

規格需求

   
最低支援的用戶端 Windows 8.1、Windows Vista [傳統型應用程式 |UWP 應用程式]
最低支援的伺服器 Windows Server 2003 [傳統型應用程式 |UWP 應用程式]
目標平台 Windows
標頭 winsock2.h
程式庫 Ws2_32.lib
Dll Ws2_32.dll

另請參閱

WSABUF

WSACloseEvent

WSAConnect

WSACreateEvent

WSAGetOverlappedResult

WSAOVERLAPPED

WSASocket

WSAWaitForMultipleEvents

Winsock 函式

Winsock 參考

connect

send

socket