标题：WSASend()
语法
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 codeMeaningWSAEACCESThe requested address is a broadcast address, but the appropriate flag was not set.WSAECONNABORTEDThe virtual circuit was terminated due to a time-out or other failure.WSAECONNRESETFor 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.WSAEFAULTThe lpBuffers, lpNumberOfBytesSent, lpOverlapped, lpCompletionRoutineparameter is not totally contained in a valid part of the user address space.WSAEINTRA blocking Windows Socket 1.1 call was canceled through WSACancelBlockingCall.WSAEINPROGRESSA blocking Windows Sockets 1.1 call is in progress, or the service provider is still processing a callback function.WSAEINVALThe socket has not been bound with bindor the socket is not created with the overlapped flag.WSAEMSGSIZEThe socket is message oriented, and the message is larger than the maximum supported by the underlying transport.WSAENETDOWNThe network subsystem has failed.WSAENETRESETFor 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.WSAENOBUFSThe Windows Sockets provider reports a buffer deadlock.WSAENOTCONNThe socket is not connected.WSAENOTSOCKThe descriptor is not a socket.WSAEOPNOTSUPPMSG_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.WSAESHUTDOWNThe socket has been shut down; it is not possible to WSASendon a socket after shutdownhas been invoked with how set to SD_SEND or SD_BOTH.WSAEWOULDBLOCKWindows 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.WSANOTINITIALISEDA successful WSAStartupcall must occur before using this function.WSA_IO_PENDINGAn overlapped operation was successfully initiated and completion will be indicated at a later time.WSA_OPERATION_ABORTEDThe overlapped operation has been canceled due to the closure of the socket, the execution of the "SIO_FLUSH" command in WSAIoctl, 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, on connectionless sockets that have a stipulated default peer address established through the connector WSAConnectfunction.
对于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: The WSASendfunction does not support more than 16 buffers.
NoteWSASend的成功完成不代表数据已经发送成功。
使用dwFlasgs参数
The dwFlags parameter 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 the dwFlags parameter. The latter is constructed by using the bitwise OR operator with any of any of the values listed in the following table. 
ValueMeaningMSG_DONTROUTESpecifies that the data should not be subject to routing. A Windows Sockets service provider can choose to ignore this flag.MSG_OOBSend OOB data on a stream-style socket such as SOCK_STREAM only.MSG_PARTIALSpecifies that lpBuffersonly contains a partial message. Be aware that the error code WSAEOPNOTSUPPwill 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, or WSASendTo. 这可以让时间敏感的数据传送得到更高的优先级（似乎也就是说你如果想让数据发得快一点，它就给你个机会快一点）。
在重叠操作期间，lpOverlapped指向的数据必须一直是合法的（你别弄些局部变量放进去:-) ）。如果同时有多个未决的IO操作，每一个操作必须有单独的WSAOVERLAPPED结构。
如果lpCompletionRoutine为空, 当操作完成时，如果lpOverlapped里面的hEvent是一个合法的event对象，系统会设置这个event为有信号（signaled ）。用户的应用程序可以用WSAWaitForMultipleEventsor WSAGetOverlappedResult来等待这个事件。
如果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 incoming connection 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;
}
运行条件
ClientRequires Windows Vista, Windows XP, Windows 2000 Professional, Windows NT Workstation 3.51 and later, Windows Me, Windows 98, or Windows 95.ServerRequires Windows Server "Longhorn", Windows Server 2003, Windows 2000 Server, or Windows NT Server 3.51 and later.HeaderDeclared in Winsock2.h.LibraryUse Ws2_32.lib.DLLRequires Ws2_32.dll.