recv 函数 (winsock.h)
recv 函数从连接的套接字或绑定的无连接套接字接收数据。
语法
int recv(
[in] SOCKET s,
[out] char *buf,
[in] int len,
[in] int flags
);
参数
[in] s
标识连接的套接字的描述符。
[out] buf
指向用于接收传入数据的缓冲区的指针。
[in] len
buf 参数指向的缓冲区的长度(以字节为单位)。
[in] flags
影响此函数行为的一组标志。 请参阅下面的备注。 有关此参数的可能值的详细信息,请参阅“备注”部分。
返回值
如果未发生错误, recv 将返回收到的字节数, buf 参数指向的缓冲区将包含接收的此数据。 如果连接已正常关闭,则返回值为零。
否则,将返回值 SOCKET_ERROR,并且可以通过调用 WSAGetLastError 来检索特定的错误代码。
错误代码 | 含义 |
---|---|
在使用此函数之前,必须成功调用 WSAStartup 。 | |
网络子系统失败。 | |
buf 参数未完全包含在用户地址空间的有效部分。 | |
套接字未连接。 | |
(阻止) 调用已通过 WSACancelBlockingCall 取消。 | |
阻止 Windows Sockets 1.1 调用正在进行,或者服务提供程序仍在处理回调函数。 | |
对于面向连接的套接字,此错误表示连接已中断,因为 保持活动 活动检测到操作正在进行时失败。 对于数据报套接字,此错误显示生存时间已经过期。 | |
:描述符不是套接字。 | |
MSG_OOB已指定,但套接字不是流样式(如类型SOCK_STREAM),与此套接字关联的通信域中不支持 OOB 数据,或者套接字是单向的,仅支持发送操作。 | |
套接字已关闭;调用关闭后,无法接收套接字上的SD_RECEIVE或SD_BOTH。 | |
套接字标记为非阻止,接收操作将阻止。 | |
消息太大,无法放入指定的缓冲区,并且已被截断。 | |
套接字未绑定 绑定,或者指定了未知标志,或者为启用了SO_OOBINLINE的套接字指定了MSG_OOB,或者仅对字节流套接字 () len 为零或负数。 | |
由于超时或其他故障,虚拟线路已终止。 因为套接字不可再用,应用程序应关闭套接字。 | |
因为网络故障或对等系统无法响应,已经丢弃了连接。 | |
执行硬性或异常关闭的远程端重置了虚拟线路。 因为套接字不可再用,应用程序应关闭套接字。 在 UDP 数据报套接字上,此错误将指示以前的发送操作导致 ICMP“端口无法访问”消息。 |
注解
recv 函数用于读取面向连接的套接字或无连接套接字上的传入数据。 使用面向连接的协议时,必须在调用 recv 之前连接套接字。 使用无连接协议时,必须在调用 recv 之前绑定套接字。
套接字的本地地址必须是已知的。 对于服务器应用程序,请使用显式 绑定 函数或隐式 accept 或 WSAAccept 函数。 不建议对客户端应用程序进行显式绑定。 对于客户端应用程序,套接字可以使用 connect、 WSAConnect、 sendto、 WSASendTo 或 WSAJoinLeaf 隐式绑定到本地地址。
对于连接的或无连接的套接字, recv 函数限制接收消息的地址。 函数仅返回来自连接中指定的远程地址的消息。 来自其他地址的消息 (静默) 丢弃。
对于面向连接的套接字 (类型SOCK_STREAM例如) ,调用 recv 将返回当前可用的数据量,最大为指定的缓冲区大小。 如果已将套接字配置为对 OOB 数据进行内联接收, (套接字选项SO_OOBINLINE) 且 OOB 数据尚未读取,则仅返回 OOB 数据。 应用程序可以使用 ioctlsocket 或 WSAIoctlSIOCATMARK 命令来确定是否还有更多 OOB 数据需要读取。
对于 (类型SOCK_DGRAM或其他面向消息的套接字) 的无连接套接字,数据从 连接 函数指定的目标地址提取第一个排队数据报 (消息) 。
如果数据报或消息大于指定的缓冲区,则会使用数据报的第一部分填充缓冲区,而 recv 将生成错误 WSAEMSGSIZE。 例如,对于不可靠的协议 (,UDP) 会丢失多余的数据;对于可靠的协议,数据由服务提供商保留,直到使用足够大的缓冲区调用 recv 成功读取。
如果套接字上没有可用的传入数据, 则 recv 调用会根据为 WSARecv 定义的阻止规则阻止并等待数据到达,除非套接字为非阻止,否则不会设置MSG_PARTIAL标志。 在这种情况下,返回值 SOCKET_ERROR,错误代码设置为 WSAEWOULDBLOCK。 select、WSAAsyncSelect 或 WSAEventSelect 函数可用于确定何时到达更多数据。
如果套接字面向连接,并且远程端已正常关闭连接,并且已接收所有数据, 则 recv 将立即完成,且接收了零个字节。 如果连接已重置, 则 recv 将失败,并显示 错误 WSAECONNRESET。
flags 参数可用于影响为关联套接字指定的选项之外的函数调用行为。 此函数的语义由套接字选项和 flags 参数确定。 flags 参数的可能值是使用以下任一值的按位 OR 运算符构造的。
值 | 含义 |
---|---|
MSG_PEEK | 查看传入数据。 数据将复制到缓冲区中,但不会从输入队列中删除。 |
MSG_OOB | 处理带外 (OOB) 数据。 |
MSG_WAITALL | 仅当发生以下事件之一时,接收请求才会完成:
|
示例代码
下面的代码示例演示如何使用 recv 函数。#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <Ws2tcpip.h>
#include <stdio.h>
// Link with ws2_32.lib
#pragma comment(lib, "Ws2_32.lib")
#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT "27015"
int __cdecl main() {
//----------------------
// Declare and initialize variables.
WSADATA wsaData;
int iResult;
SOCKET ConnectSocket = INVALID_SOCKET;
struct sockaddr_in clientService;
char *sendbuf = "this is a test";
char recvbuf[DEFAULT_BUFLEN];
int recvbuflen = DEFAULT_BUFLEN;
//----------------------
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != NO_ERROR) {
printf("WSAStartup failed: %d\n", iResult);
return 1;
}
//----------------------
// Create a SOCKET for connecting to server
ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ConnectSocket == INVALID_SOCKET) {
printf("Error at socket(): %ld\n", WSAGetLastError() );
WSACleanup();
return 1;
}
//----------------------
// The sockaddr_in structure specifies the address family,
// IP address, and port of the server to be connected to.
clientService.sin_family = AF_INET;
clientService.sin_addr.s_addr = inet_addr( "127.0.0.1" );
clientService.sin_port = htons( 27015 );
//----------------------
// Connect to server.
iResult = connect( ConnectSocket, (SOCKADDR*) &clientService, sizeof(clientService) );
if ( iResult == SOCKET_ERROR) {
closesocket (ConnectSocket);
printf("Unable to connect to server: %ld\n", WSAGetLastError());
WSACleanup();
return 1;
}
// Send an initial buffer
iResult = send( ConnectSocket, sendbuf, (int)strlen(sendbuf), 0 );
if (iResult == SOCKET_ERROR) {
printf("send failed: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 1;
}
printf("Bytes Sent: %ld\n", iResult);
// shutdown the connection since no more data will be sent
iResult = shutdown(ConnectSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
printf("shutdown failed: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 1;
}
// Receive until the peer closes the connection
do {
iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
if ( iResult > 0 )
printf("Bytes received: %d\n", iResult);
else if ( iResult == 0 )
printf("Connection closed\n");
else
printf("recv failed: %d\n", WSAGetLastError());
} while( iResult > 0 );
// cleanup
closesocket(ConnectSocket);
WSACleanup();
return 0;
}
示例代码
有关详细信息,以及 recv 函数的另一个示例,请参阅 入门 With Winsock。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 |
标头 | winsock.h (包括 Winsock2.h) |
Library | Ws2_32.lib |
DLL | Ws2_32.dll |