WSASend()

WSASend()

WSASend函式:在一個已連線的套接口上傳送數據。

基本介紹

  • 中文名:WSASend()
  • 作用:在一個已連線的套接口上傳送數據
  • Count:參數為WSABUF結構的數目
  • dwFlags:標誌位
簡述,語法,參數,返回值,評述,使用參數,操作,運行條件,

簡述

語法

int WSASend (
SOCKET s,
LPWSABUF lpBuffers
DWORD dwBufferCount,
LPDWORD lpNumberOfBytesSent,
DWORD dwFlags,
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);

參數

s:標識一個已連線套接口的描述字。
lpBuffers:一個指向WSABUF結構數組指針。每個WSABUF結構包含緩衝區的指針和緩衝區的大小。
dwBufferCount:lpBuffers數組中WSABUF結構的數目。
lpNumberOfBytesSent:如果傳送操作立即完成,則為一個指向所傳送數據位元組數的指針。
dwFlags:標誌位。
lpOverlapped:指向WSAOVERLAPPED結構的指針(對於非重疊套接口則忽略)。
lpCompletionRoutine:一個指向傳送操作完成後調用的完成例程的指針。(對於非重疊套接口則忽略)。

返回值

若無錯誤發生且傳送操作立即完成,則WSASend()函式返回0。這時,完成例程(Completion Routine)應該已經被調度,一旦調用執行緒處於alertable狀態時就會調用它。否則,返回SOCKET_ERROR 。通過WSAGetLastError獲得詳細的錯誤代碼。WSA_IO_PENDING 這個錯誤碼(其實表示沒有錯誤)表示重疊操作已經提交成功(就是異步IO的意思了),稍後會提示完成(這個完成可不一定是傳送成功,沒準出問題也不一定)。其他的錯誤代碼都代表重疊操作沒有正確開始,也不會有完成標誌出現。
Error code
Meaning
WSAEACCES
The requested address is a broadcast address, but the appropriate flag was not set.
WSAECONNABORTED
The virtual circuit was terminated due to a time-out or other failure.
WSAECONNRESET
For a stream socket, the virtual circuit was reset by the remote side. The application should close the socket as it is no longer useable. For a UDP datagram socket, this error would indicate that a previous send operation resulted in an ICMP "Port Unreachable" message.
WSAEFAULT
ThelpBuffers,lpNumberOfBytesSent,lpOverlapped,lpCompletionRoutineparameter is not totally contained in a valid part of the user address space.
WSAEINTR
A blocking Windows Socket 1.1 call was canceled throughWSACancelBlockingCall.
WSAEINPROGRESS
A blocking Windows Sockets 1.1 call is in progress, or the service provider is still processing a callback function.
WSAEINVAL
The socket has not been bound withbindor the socket is not created with the overlapped flag.
WSAEMSGSIZE
The socket is message oriented, and the message is larger than the maximum supported by the underlying transport.
WSAENETDOWN
The network subsystem has failed.
WSAENETRESET
For a stream socket, the connection has been broken due to keep-alive activity detecting a failure while the operation was in progress. For a datagram socket, this error indicates that the time to live has expired.
WSAENOBUFS
The Windows Sockets provider reports a buffer deadlock.
WSAENOTCONN
The socket is not connected.
WSAENOTSOCK
The descriptor is not a socket.
WSAEOPNOTSUPP
MSG_OOB was specified, but the socket is not stream-style such as type SOCK_STREAM, OOB data is not supported in the communication domain associated with this socket, MSG_PARTIAL is not supported, or the socket is unidirectional and supports only receive operations.
WSAESHUTDOWN
The socket has been shut down; it is not possible toWSASendon a socket aftershutdownhas been invoked with how set to SD_SEND or SD_BOTH.
WSAEWOULDBLOCK
Windows NT:Overlapped sockets: There are too many outstanding overlapped I/O requests. Nonoverlapped sockets: The socket is marked as nonblocking and the send operation cannot be completed immediately.
WSANOTINITIALISED
A successfulWSAStartupcall must occur before using this function.
WSA_IO_PENDING
An overlapped operation was successfully initiated and completion will be indicated at a later time.
WSA_OPERATION_ABORTED
The overlapped operation has been canceled due to the closure of the socket, the execution of the "SIO_FLUSH" command inWSAIoctl, or the thread that initiated the overlapped request exited before the operation completed. For more information, see the Remarks section.

評述

WSASend覆蓋標準的send函式,並在下面兩個方面有所增強:
>它可以用於overlapped socket(重疊socket)上以進行重疊傳送的操作(簡單地理解為就是異步send也可以了)
>它可以一次傳送多個緩衝區中的數據來進行集中寫入。應該相當於unix上的writev,好處看來是避免Nagle算法
WSASend用於在一個面向連線的socket(第一個參數s)上發出的數據。It can also be used, however, onconnectionless sockets that have a stipulated default peer address established through theconnectorWSAConnectfunction.
對於overlapped sockets來說 (通過WSASocket函式,用WSA_FLAG_OVERLAPPED標示創建),傳送訊息時使用的是重疊IO(overlapped I/O), 除非lpOverlapped and lpCompletionRoutine 都是NULL. 這時, 這個socket被視為非重疊的socket. 當所有的緩衝區都被傳送完成了,將會執行一個動作來表示操作完成,這個動作可能是調用完成例程或者是引發一個event對象。如果操作沒有立即完成, 最終的完成狀態通過完成例程或者 WSAGetOverlappedResult得到
對於非重疊的sockets來說, 最後兩個參數(lpOverlapped, lpCompletionRoutine) 被忽略,WSASend 和 send具有同樣的語意。數據從用戶緩衝區拷貝到傳送緩衝區中(應該是指系統的socket堆疊)。如果socket是非阻塞的又是同時是面向流的(簡單地理解為tcp), 同時傳送緩衝區沒有足夠的大小, WSASend將只傳送用戶緩衝區中的部分數據。 如果同樣快取大小,而socke是阻塞的socket, WSASend將阻塞直到用戶所有的數據被傳送成功。
Note socket配置項SO_RCVTIMEO and SO_SNDTIMEO只能被用於阻塞的sockets
lpBuffers這個參數是一個指針,它指向一個WSABUF結構的數組。這個數組可以是瞬態的(transient)。所謂瞬態的含義如下:如果這個操作時重疊的操作,服務提供者有責任在這個調用返回之前保存WSABUF數組。這允許用戶的套用使用一個基於棧的WSABUF數組。就是說你可以定義一個局部變數,當wsasend返回後如果是重疊IO呢,你的函式局部變數已經被銷毀了(例如你的函式已經返回了)。系統實際上還沒傳送數據呢,那你不要擔心,系統會保存這個數組的副本。
對於面向訊息的socket(UDP?), 不要超過下層協定的最大訊息大小,這個值可以通過SO_MAX_MSG_SIZE這個socket配置項得到。如果數據太長無法原子地傳送,返回WSAEMSGSIZE, 沒有數據傳送成功。
Windows Me/98/95:TheWSASendfunction does not support more than 16 buffers.
NoteWSASend的成功完成不代表數據已經傳送成功。

使用參數

ThedwFlagsparameter can be used to influence the behavior of the function invocation beyond the options specified for the associated socket. That is, the semantics of this function are determined by the socket options and thedwFlagsparameter. The latter is constructed by using the bitwise OR operator with any of any of the values listed in the following table.
Value
Meaning
MSG_DONTROUTE
Specifies that the data should not be subject to routing. A Windows Sockets service provider can choose to ignore this flag.
MSG_OOB
Send OOB data on a stream-style socket such as SOCK_STREAM only.
MSG_PARTIAL
Specifies thatlpBuffersonly contains a partial message. Be aware that the error codeWSAEOPNOTSUPPwill be returned by transports that do not support partial message transmissions.

操作

Overlapped Socket I/O
如果重疊操作立即完成,WSASend返回0 同時設定lpNumberOfBytesSent指向的變數為傳送的位元組數。如果重疊操作成功初始化將稍後完成,WSASend返回 SOCKET_ERROR同時設定錯誤碼為WSA_IO_PENDING. 這時,lpNumberOfBytesSent指向的變數不會被更新。當重疊IO完成以後,傳送的數量可以用兩種方式取得:如果指定了完成例程(即lpCompletionRoutine),那么通過完成例程的cbTransferred參數得到。也可以調用WSAGetOverlappedResult,通過lpcbTransfer得到。
Note如果一個執行緒退出了,那么它發出的IO操作都將取消。對於重疊sockets來說, 如果在操作完成之前,執行緒被關閉了,未決的異步操作可能會失敗,更詳細的信息, 參見ExitThread
WSASend可以在下列函式的完成例程中調用:WSARecv,WSARecvFrom,WSASend, orWSASendTo. 這可以讓時間敏感的數據傳送得到更高的優先權(似乎也就是說你如果想讓數據發得快一點,它就給你個機會快一點)。
在重疊操作期間,lpOverlapped指向的數據必須一直是合法的(你別弄些局部變數放進去:-) )。如果同時有多個未決的IO操作,每一個操作必須有單獨的WSAOVERLAPPED結構。
如果lpCompletionRoutine為空, 當操作完成時,如果lpOverlapped裡面的hEvent是一個合法的event對象,系統會設定這個event為有信號(signaled )。用戶的應用程式可以用WSAWaitForMultipleEventsorWSAGetOverlappedResult來等待這個事件。
如果lpCompletionRoutine非空,hEvent被忽略,它可以被用於傳送上下文信息給完成例程。如果調用方設定了一個非空的lpCompletionRoutine隨後又在同樣的重疊IO上調用WSAGetOverlappedResult又沒有設定WSAGetOverlappedResult 的參數為TRUE. 這時hEvent是未定義的,同時等待hEvent也將產生不預知的結果。(就是說你不要同時用完成例程WSAGetOverlappedResult或者hevnet)。
這裡的完成例程和windows檔案IO的完成例程一樣。一直到有執行緒處於alertable wait state狀態時,完成例程才會被調用,例如調用WSAWaitForMultipleEvents並設定fAlertable為TRUE。
數據傳送層(transport providers )允許用戶在重疊socket的完成例程里發出send和receive調用,同時保證對於一個給定的socket,IO的完成例程不會嵌套。這可以讓時間敏感的數據傳送得到更高的優先權
下面的代碼是完成例程的原型:
The following C++ code example is a prototype of the completion routine.
void CALLBACK CompletionROUTINE(
IN DWORD dwError,
IN DWORD cbTransferred,
IN LPWSAOVERLAPPED lpOverlapped,
IN DWORD dwFlags
);
完成例程不過是用戶定義的一個函式的占位符而已。(就是說它是個回調函式)dwError說明重疊IO完成的狀態,這個重疊IO由lpOverlapped指定。cbTransferred是傳送的位元組數。當前沒有使用dwFlags,他總是被設為0。該函式沒有返回值。
Returning from this function allows invocation of another pending completion routine for this socket. All waiting completion routines are called before the alertable thread's wait is satisfied with a return code of WSA_IO_COMPLETION. 完成例程可能以任何次序被調用,不必是重疊IO完成的次序。但是提交傳送的多個緩衝區會確保按照指定的次序傳送。
如果你使用完成連線埠,要注意調用WSASend的次序就是就是緩衝區被填充的次序。不要從不同的執行緒中同時調用同一個socket上的WSASend函式,因為可能導致緩衝區中的數據處於不可預知的次序。
Example Code
下面的代碼演示如何以重疊IO的方式使用WSASend函式。
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <stdlib.h>
#define DATA_BUFSIZE 4096
#define SEND_COUNT 10
void __cdecl main()
{
WSADATA wsd;
struct addrinfo *result = NULL,
hints = ;
WSAOVERLAPPED SendOverlapped = ;
SOCKET ListenSocket = INVALID_SOCKET,
AcceptSocket = INVALID_SOCKET;
WSABUF DataBuf;
DWORD SendBytes, Flags;
char buffer[DATA_BUFSIZE];
int err, rc, i;
// Load Winsock
rc = WSAStartup(MAKEWORD(2,2), &wsd);
if (rc != 0) {
fprintf(stderr, "Unable to load Winsock: %d\n", rc);
return;
}
// Initialize the hints to obtain the
// wildcard bind address for IPv4
hintsai_family = AF_INET;
hintsai_socktype = SOCK_STREAM;
hintsai_protocol = IPPROTO_TCP;
hintai_flags = AI_PASSIVE;
rc =getaddrinfo(NULL, "27015", &hints, &result);
if (rc != 0) {
fprintf(stderr, "getaddrinfo failed: %d\n", rc );
return;
}
ListenSocket = socket(result->ai_family,
result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET) {
fprintf(stderr, "socket failed: %d\n",
WSAGetLastError());
freeaddrinfo(result);
return;
}
rc = bind(ListenSocket, result->ai_addr,
(int)result->ai_addrlen);
if (rc == SOCKET_ERROR) {
fprintf(stderr, "bind failed: %d\n",
WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
return;
}
rc = listen(ListenSocket, 1);
if (rc == SOCKET_ERROR) {
fprintf(stderr, "listen failed: %d\n",
WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
return;
}
// Accept an incomingconnection request
AcceptSocket = accept(ListenSocket, NULL, NULL);
if (AcceptSocket == INVALID_SOCKET) {
fprintf(stderr, "accept failed: %d\n",
WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
return;
}
printf("Client Accepted...\n");
// Create an event handle and setup an overlapped structure.
SendOverlapped.hEvent =WSACreateEvent();
if (SendOverlapped.hEvent == NULL) {
fprintf(stderr, "WSACreateEvent failed: %d\n",
WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
closesocket(AcceptSocket);
return;
}
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()))) {
fprintf(stderr, "WSASend failed: %d\n", err);
break;
}
rc = WSAWaitForMultipleEvents(1, &SendOverlapped.hEvent, TRUE, INFINITE, TRUE);
if (rc == WSA_WAIT_FAILED) {
fprintf(stderr, "WSAWaitForMultipleEvents failed: %d\n", WSAGetLastError());
break;
}
rc = WSAGetOverlappedResult(AcceptSocket, &SendOverlapped, &SendBytes, FALSE, &Flags);
if (rc == FALSE) {
fprintf(stderr, "WSASend operation failed: %d\n", WSAGetLastError());
break;
}
printf("Wrote %d bytes\n", SendBytes);
WSAResetEvent(SendOverlapped.hEvent);
}
WSACloseEvent(SendOverlapped.hEvent);
closesocket(AcceptSocket);
closesocket(ListenSocket);
freeaddrinfo(result);
WSACleanup();
return;
}

運行條件

Client
Requires Windows Vista, Windows XP, Windows 2000 Professional, Windows NT Workstation 3.51 and later, Windows Me, Windows 98, or Windows 95.
Server
Requires Windows Server "Longhorn", Windows Server 2003, Windows 2000 Server, or Windows NT Server 3.51 and later.
Header
Declared in Winsock2.h.
Library
Use Ws2_32.lib.
DLL
Requires Ws2_32.dll.

相關詞條

熱門詞條

聯絡我們