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 函数调用行为的标志。 有关详细信息,请参阅“备注”部分中的 Using 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 套接字 1.1 调用已通过 WSACancelBlockingCall 取消。 | |
阻止 Windows Sockets 1.1 调用正在进行,或者服务提供程序仍在处理回调函数。 | |
套接字未绑定 绑定, 或者未使用重叠标志创建套接字。 | |
套接字面向消息,消息大于基础传输支持的最大大小。 | |
网络子系统失败。 | |
对于流套接字,连接已中断,因为保持活动活动检测到操作正在进行时失败。 对于数据报套接字,此错误显示生存时间已经过期。 | |
Windows 套接字提供程序报告缓冲区死锁。 | |
套接字未连接。 | |
:描述符不是套接字。 | |
MSG_OOB 已指定,但套接字不是流样式(如 类型SOCK_STREAM),与此套接字关联的通信域中不支持 OOB 数据, MSG_PARTIAL 不受支持,或者套接字是单向的,仅支持接收操作。 | |
套接字已关闭;在调用关闭后,无法在套接字上发送 WSASend,其方式设置为 SD_SEND 或 SD_BOTH。 | |
Windows NT:
重叠套接字:存在过多未完成的重叠 I/O 请求。 未重叠的套接字:套接字标记为非阻止,并且无法立即完成发送操作。 |
|
在使用此函数之前,必须成功调用 WSAStartup 。 | |
已成功启动重叠操作,稍后将指示完成。 | |
由于套接字关闭、 WSAIoctl 中的“SIO_FLUSH”命令的执行或启动重叠请求的线程在操作完成之前退出,重叠操作已取消。 有关详细信息,请参阅“备注”部分。 |
备注
WSASend 函数在两个重要方面提供高于标准发送函数的功能:
WSASend 函数用于从 指定的面向连接的套接字上的一个或多个缓冲区写入传出数据。 但是,它也可用于具有通过 connect 或 WSAConnect 函数建立的指定默认对等地址的无连接套接字。由套接字函数创建的 套接字 将具有重叠属性作为默认值。 WSASocket 函数创建的套接字具有将 dwFlags 参数传递给 WSASocket 的WSA_FLAG_OVERLAPPED位集将具有重叠属性。 对于具有重叠属性的套接字, WSASend 使用重叠 I/O,除非 lpOverlapped 和 lpCompletionRoutine 参数均为 NULL。 在这种情况下,套接字被视为非重叠套接字。 当传输已使用缓冲区 (s) 时,将发生完成指示,调用事件对象的例程或设置完成。 如果操作未立即完成,则通过完成例程或 WSAGetOverlappedResult 检索最终完成状态。
如果 lpOverlapped 和 lpCompletionRoutine 均为 NULL,则此函数中的套接字将被视为非重叠套接字。
对于非重叠套接字,将忽略最后两个参数 (lpOverlapped、lpCompletionRoutine) ,WSASend 采用与 send 相同的阻止语义。 数据从缓冲区 () 复制到传输的缓冲区中。 如果套接字是非阻塞和面向流的,并且传输的缓冲区中没有足够的空间, 则 WSASend 将返回,只使用应用程序的一部分缓冲区。 给定相同的缓冲区情况和阻止套接字, WSASend 将阻止,直到所有应用程序缓冲区内容都已使用。
对于面向消息的套接字,请勿超过基础提供程序的最大消息大小,可通过获取 套接字选项的值SO_MAX_MSG_SIZE获取。 如果数据太长,无法通过基础协议以原子方式传递,则返回错误 WSAEMSGSIZE ,并且不传输任何数据。
Windows Me/98/95: WSASend 函数不支持超过 16 个缓冲区。
使用 dwFlags
dwFlags 参数可用于影响函数调用的行为,超出为关联套接字指定的选项。 也就是说,此函数的语义由套接字选项和 dwFlags 参数确定。 后者是通过将按位 OR 运算符与下表中列出的任何值结合使用来构造的。值 | 含义 |
---|---|
MSG_DONTROUTE | :指定数据不应受到路由的约束。 Windows 套接字服务提供程序可以选择忽略此标志。 |
MSG_OOB | 仅在流式套接字(例如 SOCK_STREAM )上发送 OOB 数据。 |
MSG_PARTIAL | 指定 lpBuffers 仅包含部分消息。 请注意,不支持部分消息传输的传输将返回错误代码 WSAEOPNOTSUPP 。 |
重叠套接字 I/O
如果重叠操作立即完成, WSASend 将返回零值,并使用发送的字节数更新 lpNumberOfBytesSent 参数。 如果重叠操作已成功启动并将稍后完成, 则 WSASend 将返回SOCKET_ERROR并指示 错误代码WSA_IO_PENDING。 在这种情况下,不会更新 lpNumberOfBytesSent 。 当重叠操作完成时,将通过完成例程 (中的 cbTransferred 参数(如果指定) )或通过 WSAGetOverlappedResult 中的 lcbTransfer 参数指示传输的数据量。lpOverlapped 参数必须在重叠操作期间有效。 如果多个 I/O 操作同时未完成,则每个操作都必须引用单独的 WSAOVERLAPPED 结构。
如果 lpCompletionRoutine 参数为 NULL,则当重叠操作完成时,如果它包含有效的事件对象句柄,则会向 lpOverlapped 的 hEvent 参数发出信号。 应用程序可以使用 WSAWaitForMultipleEvents 或 WSAGetOverlappedResult 等待或轮询事件对象。
如果 lpCompletionRoutine 不为 NULL,则 忽略 hEvent 参数,应用程序可以使用该参数将上下文信息传递给完成例程。 为同一重叠 I/O 请求传递非 NULLlpCompletionRoutine 并随后调用 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.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 |
Library | Ws2_32.lib |
DLL | Ws2_32.dll |