LPWSPRECV 回调函数 (ws2spi.h)

LPWSPRecv 函数接收套接字上的数据。

语法

LPWSPRECV Lpwsprecv;

int Lpwsprecv(
  [in]         SOCKET s,
  \[in\, out\] LPWSABUF lpBuffers,
  [in]         DWORD dwBufferCount,
  [out]        LPDWORD lpNumberOfBytesRecvd,
  \[in\, out\] LPDWORD lpFlags,
  [in]         LPWSAOVERLAPPED lpOverlapped,
  [in]         LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
  [in]         LPWSATHREADID lpThreadId,
  [out]        LPINT lpErrno
)
{...}

参数

[in] s

标识已连接套接字的描述符。

\\[in\\, out\\] lpBuffers

指向 WSABUF 结构数组的指针。 每个 WSABUF 结构都包含指向缓冲区的指针和缓冲区的长度(以字节为单位)。

[in] dwBufferCount

lpBuffers 数组中的 WSABUF 结构数。

[out] lpNumberOfBytesRecvd

指向此调用接收的字节数的指针。

\\[in\\, out\\] lpFlags

指向指定调用方式的标志的指针。

[in] lpOverlapped

指向 WSAOverlapped 结构的指针 (忽略非重叠结构) 。

[in] lpCompletionRoutine

类型:_In_opt_ LPWSAOVERLAPPED_COMPLETION_ROUTINE

指向完成接收操作时调用的完成例程的指针, (忽略) 未重叠结构。

[in] lpThreadId

指向 WSATHREADID 结构的指针,供提供程序在后续调用 WPUQueueApc 时使用。 在 WPUQueueApc 函数返回之前,提供程序应存储引用的 WSATHREADID 结构 (而不是指向同一) 的指针。

[out] lpErrno

指向错误代码的指针。

返回值

如果未发生任何错误,并且接收操作已立即完成, LPWSPRecv 将返回零。 请注意,在这种情况下,完成例程(如果指定)已排队。 否则,返回值 SOCKET_ERROR,并在 lpErrno 中提供特定的错误代码。 错误代码WSA_IO_PENDING指示重叠操作已成功启动,稍后将指示完成。 任何其他错误代码指示未启动重叠的操作,并且不会发生完成指示。

错误代码 含义
WSAENETDOWN
网络子系统失败。
WSAENOTCONN
套接字未连接。
WSAEINTR
(阻止) 调用已通过 LPWSPCancelBlockingCall 取消。
WSAEINPROGRESS
正在阻止 Windows 套接字调用,或者服务提供程序仍在处理回调函数。
WSAENETRESET
由于操作执行过程中持续的活动检测到故障,连接损坏。
WSAEFAULT
lpBuffers 参数并不完全包含在用户地址空间的有效部分。
WSAENOTSOCK
:描述符不是套接字。
WSAEOPNOTSUPP
MSG_OOB已指定,但套接字不是流样式(如类型SOCK_STREAM),与此套接字关联的通信域中不支持 OOB 数据,或者套接字是单向的,仅支持发送操作。
WSAESHUTDOWN
套接字已关闭;调用 LPWSPShutdown 后,无法通过套接字上的 LPWSPRecv 接收SD_RECEIVE或SD_BOTH。
WSAEWOULDBLOCK
Windows NT:重叠套接字:存在过多未完成的重叠 I/O 请求。 未重叠的套接字:套接字标记为非阻塞,接收操作无法立即完成。
WSAEMSGSIZE
消息太大,无法放入指定的缓冲区,对于不可靠的协议, (仅) 消息的任何尾随部分不适合缓冲区已被丢弃。
WSAEINVAL
套接字尚未绑定 (例如,使用 LPWSPBind) ,或者未使用重叠标志创建套接字。
WSAECONNABORTED
虚拟线路因超时或其他故障而终止。
WSAECONNRESET
远程端重置了虚拟线路。
WSAEDISCON
套接字面向消息,虚拟线路由远程端正常关闭。
WSA_IO_PENDING
已成功启动重叠操作,稍后将指示完成。
WSA_OPERATION_ABORTED
由于套接字关闭,重叠操作已取消。

注解

LPWSPRecv 用于 s 参数指定的 连接套接字或绑定无连接套接字,用于读取传入数据。 套接字的本地地址必须是已知的。 这可以通过 LPWSPBind 显式完成,也可以通过 LPWSPAcceptLPWSPConnectLPWSPSendToLPWSPJoinLeaf 隐式完成。

对于连接的无连接套接字,此函数限制接收消息的地址。 函数仅返回来自连接中指定的远程地址的消息。 来自其他地址的消息 (静默) 丢弃。

对于重叠套接字 ,LPWSPRecv 用于在传入数据可用时将一个或多个缓冲区发布到其中,之后 Windows 套接字 SPI 客户端指定的完成指示 (调用完成例程或事件对象的设置) 。 如果操作未立即完成,则通过完成例程或 LPWSPGetOverlappedResult 检索最终完成状态。

如果 lpOverlappedlpCompletionRoutine 均为 null,则此函数中的套接字将被视为非重叠套接字。

对于非重叠套接字,将忽略 lpOverlappedlpCompletionRoutinelpThreadId 参数。 传输已接收和缓冲的任何数据都将复制到提供的用户缓冲区中。 对于传输当前没有接收和缓冲数据的阻塞套接字,调用将阻塞,直到收到数据。 Windows 套接字 2 不为此函数定义任何标准阻止超时机制。 对于充当字节流协议的协议,堆栈会尝试根据提供的缓冲区空间和可用接收的数据量返回尽可能多的数据。 但是,接收单个字节足以取消阻止调用方。 不能保证返回的字节超过一个。 对于充当面向消息的协议,需要完整消息来取消阻止调用方。

协议是否充当字节流 取决于其WSAPROTOCOL_INFO 结构中的XP1_MESSAGE_ORIENTED和XP1_PSEUDO_STREAM设置,以及传递给此函数的MSG_PARTIAL标志的设置, (支持它的协议) 。 下表汇总了相关组合, (星号 (*) 指示此位的设置在此示例中) 无关紧要。

XP1_MESSAGE_ORIENTED XP1_PSEUDO_STREAM MSG_PARTIAL 充当
未设置 * * 字节流
* 设置 * 字节流
设置 未设置 设置 字节流
设置 未设置 未设置 面向消息

提供的缓冲区按它们在 lpBuffers 指向的数组中的出现顺序进行填充,并打包缓冲区,以便不创建任何孔。

lpBuffers 参数指向的 WSABUF 结构数组是暂时性的。 如果此操作以重叠方式完成,则服务提供商负责在从此调用返回之前捕获指向 WSABUF 结构的此指针数组。 这使 Windows 套接字 SPI 客户端能够生成基于堆栈的 WSABUF 数组。

例如,对于字节流样式套接字 (类型SOCK_STREAM) ,传入数据将放入缓冲区,直到填充缓冲区、关闭连接或内部缓冲的数据耗尽。 无论传入数据是否填充所有缓冲区,重叠套接字都会显示完成指示。 例如,对于面向消息的套接字 (类型SOCK_DGRAM) ,传入消息将放入提供的缓冲区中,最大大小为提供的缓冲区的总大小,重叠套接字会出现完成指示。 如果消息大于提供的缓冲区,则缓冲区将填充消息的第一部分。 如果服务提供程序支持MSG_PARTIAL功能,则会在 lpFlags 中设置MSG_PARTIAL标志,后续接收操作 () 可用于检索消息的其余部分。 如果不支持MSG_PARTIAL,但协议可靠, 则 LPWSPRecv 将生成错误 WSAEMSGSIZE ,并且可以使用具有较大缓冲区的后续接收操作来检索整个消息。 否则, (即协议不可靠且不支持MSG_PARTIAL) ,多余的数据将丢失, LPWSPRecv 将生成错误 WSAEMSGSIZE。

对于面向连接的套接字, LPWSPRecv 可以通过两种方式之一指示虚拟线路的正常终止,具体取决于套接字是面向字节流还是面向消息。 对于字节流,已读取的零个字节表示正常关闭,并且不再读取更多字节。 对于通常允许零字节消息的面向消息的套接字, WSAEDISCON 的返回错误代码用于指示正常关闭。 在任何情况下, WSAECONNRESET 的返回错误代码都表示发生了中止关闭。

lpFlags 参数可用于影响函数调用的行为,超出为关联套接字指定的选项。 也就是说,此函数的语义由套接字选项和 lpFlags 参数确定。 后者是使用以下任何值的按位 OR 运算符构造的。

含义
MSG_PEEK 速览传入数据。 数据会复制到缓冲区中,但不会从输入队列中删除。 此标志仅对未重叠的套接字有效。
MSG_OOB 处理带外 (OOB) 数据。
MSG_PARTIAL 此标志仅适用于面向消息的套接字。 在输出时,指示提供的数据是发送方传输的消息的一部分。 消息的剩余部分将在后续接收操作中提供。 清除了MSG_PARTIAL标志的后续接收操作指示发件人的消息结束。 作为输入参数,MSG_PARTIAL指示接收操作应完成,即使服务提供商只接收了消息的一部分。

如果重叠操作立即完成, LPWSPRecv 返回值零, lpNumberOfBytesRecvd 参数将更新为接收的字节数, lpFlags 参数指向的标志位也会更新。 如果重叠操作已成功启动并稍后完成, 则 LPWSPRecv 将返回SOCKET_ERROR并指示 错误代码WSA_IO_PENDING。 在这种情况下, lpNumberOfBytesRecvdlpFlags 不会更新。 当重叠操作完成时,通过完成例程 (中的 cbTransferred 参数(如果指定) )或通过 LPWSPGetOverlappedResult 中的 l (的lTransfer 参数指示传输的数据量。 标志值是通过完成例程的 dwFlags 参数或检查 WSAGetOverlappedResultlpdwFlags 参数获取的。

提供程序必须允许从以前的 LPWSPRecv、LPWSPRecvFromLPWSPSendLPWSPSendTo 函数的完成例程中调用此函数。 但是,对于给定的套接字,无法嵌套 I/O 完成例程。 这允许时间敏感型数据传输完全在抢占式上下文中进行。

lpOverlapped 参数在重叠操作期间必须有效。 如果多个 I/O 操作同时未完成,则每个操作都必须引用单独的重叠结构。 WSAOverlapped 结构在其自己的引用页中定义。

如果 lpCompletionRoutine 参数为 null,则当重叠操作完成时,如果包含有效的事件对象句柄,则服务提供程序会向 lpOverlappedhEvent 成员发出信号。 Windows 套接字 SPI 客户端可以使用 LPWSPGetOverlappedResult 等待或轮询事件对象。

如果 lpCompletionRoutine 不为 null,则 忽略 hEvent 成员,Windows 套接字 SPI 客户端可以使用该成员将上下文信息传递给完成例程。 为相同的重叠 I/O 请求传递 null lpCompletionRoutine 并稍后调用 WSAGetOverlappedResult 的客户端可能不会将 WSAGetOverlappedResult 调用的 fWait 参数设置为 TRUE。 在这种情况下, hEvent 成员的用法未定义,并且尝试等待 hEvent 成员将产生不可预知的结果。

当重叠操作完成时,服务提供商负责安排客户端指定的完成例程的调用。 由于必须在启动重叠操作的同一线程的上下文中执行完成例程,因此无法直接从服务提供程序调用它。 Ws2_32.dll 提供异步过程调用 (APC) 机制,以方便调用完成例程。

服务提供商通过调用 WPUQueueApc(用于启动重叠操作)安排在适当的线程和进程上下文中执行的函数。 可以从任何进程和线程上下文调用此函数,甚至是不同于用于启动重叠操作的线程和进程的上下文。

WPUQueueApc 将指向 WSATHREADID 结构的指针作为输入参数, (通过 lpThreadId 输入参数) 提供给提供程序、指向要调用的 APC 函数的指针以及随后传递给 APC 函数的上下文值。 由于只有单个上下文值可用,因此 APC 函数本身不能是客户端指定的完成例程。 服务提供商必须改为提供指向其自己的 APC 函数的指针,该函数使用提供的上下文值访问重叠操作所需的结果信息,然后调用客户端指定的完成例程。

客户端提供的完成例程的原型如下所示。

void CALLBACK 
CompletionRoutine(  
  IN DWORD           dwError, 
  IN DWORD           cbTransferred, 
  IN LPWSAOVERLAPPED lpOverlapped, 
  IN DWORD           dwFlags 
);

CompletionRoutine 参数是客户端提供的函数名称的占位符。 dwError 指定重叠操作的完成状态,如 lpOverlapped 所示。 cbTransferred 参数指定接收的字节数。 dwFlags 包含如果接收操作已立即完成,则会显示在 lpFlags 中的信息。 此函数不返回值。

可以按任何顺序调用完成例程,但不一定按照重叠操作完成的顺序调用。 但是,保证按提供缓冲区的相同顺序填充已过帐缓冲区。

注意

当给定线程退出时,将取消由给定线程启动的所有 I/O。 对于重叠套接字,如果在操作完成之前关闭线程,挂起的异步操作可能会失败。 有关详细信息 ,请参阅 ExitThread

要求

要求
最低受支持的客户端 Windows 10内部版本 20348
最低受支持的服务器 Windows 10内部版本 20348
标头 ws2spi.h

另请参阅

WPUCloseEvent

WPUCreateEvent

WPUQueueApc

LPWSPGetOverlappedResult

LPWSPSocket