recvfrom 函数 (winsock.h)
recvfrom 函数接收数据报并存储源地址。
语法
int recvfrom(
[in] SOCKET s,
[out] char *buf,
[in] int len,
[in] int flags,
[out] sockaddr *from,
[in, out, optional] int *fromlen
);
参数
[in] s
标识绑定套接字的描述符。
[out] buf
传入数据的缓冲区。
[in] len
buf 参数指向的缓冲区的长度(以字节为单位)。
[in] flags
一组选项,用于修改函数调用的行为,超出为关联套接字指定的选项。 有关更多详细信息,请参阅下面的“备注”。
[out] from
指向 sockaddr 结构中的缓冲区的可选指针,该缓冲区将在返回时保存源地址。
[in, out, optional] fromlen
指向 from 参数指向的缓冲区大小(以字节为单位)的可选指针。
返回值
如果未发生错误, recvfrom 将返回收到的字节数。 如果连接已正常关闭,则返回值为零。 否则,将返回值 SOCKET_ERROR,并且可以通过调用 WSAGetLastError 来检索特定的错误代码。
错误代码 | 含义 |
---|---|
在使用此函数之前,必须成功调用 WSAStartup 。 | |
网络子系统失败。 | |
buf 或 from 参数指向的缓冲区不在用户地址空间中,或者 fromlen 参数太小,无法容纳对等地址的源地址。 | |
(阻止) 调用已通过 WSACancelBlockingCall 取消。 | |
阻止 Windows Sockets 1.1 调用正在进行,或者服务提供程序仍在处理回调函数。 | |
套接字未绑定 绑定,或者指定了未知标志,或者为启用了SO_OOBINLINE的套接字指定了MSG_OOB,或者仅) len 为零或负数的字节流样式套接字 (。 | |
套接字已连接。 无论连接套接字是面向连接的还是无连接的套接字,都不允许使用此函数。 | |
对于数据报套接字,此错误显示生存时间已经过期。 | |
s 参数中的描述符不是套接字。 | |
MSG_OOB已指定,但套接字不是流样式(如类型SOCK_STREAM),与此套接字关联的通信域中不支持 OOB 数据,或者套接字是单向的,仅支持发送操作。 | |
套接字已关闭;在调用关闭后,无法从套接字上重新显示SD_RECEIVE或SD_BOTH。 | |
套接字标记为非阻塞, recvfrom 操作将阻止。 | |
消息太大,无法容纳 到 buf 参数指向的缓冲区中,并且被截断。 | |
由于网络故障或另一端的系统在未通知的情况下出现故障,连接已断开。 | |
执行硬性或异常关闭的远程端重置了虚拟线路。 应用程序应关闭套接字;它不再可用。 在 UDP 数据报套接字上,此错误指示以前的发送操作导致 ICMP 端口无法访问 消息。 |
注解
recvfrom 函数读取已连接和未连接的套接字上的传入数据,并捕获从中发送数据的地址。 此函数通常用于无连接套接字。 套接字的本地地址必须是已知的。 对于服务器应用程序,这通常通过 绑定显式完成。 不建议对客户端应用程序进行显式绑定。 对于使用此函数的客户端应用程序,套接字可以通过 sendto、 WSASendTo 或 WSAJoinLeaf 隐式绑定到本地地址。
对于面向流的套接字(如类型为 SOCK_STREAM 的套接字),对 recvfrom 的调用将返回当前可用的信息量(最大为指定缓冲区的大小)。 如果套接字已配置为内联接收 OOB 数据 (套接字选项SO_OOBINLINE) 且 OOB 数据尚未读取,则仅返回 OOB 数据。 应用程序可以使用 ioctlsocket 或 WSAIoctlSIOCATMARK 命令来确定是否还有更多 OOB 数据需要读取。 对于面向连接的套接字,将忽略 from 和 fromlen 参数。
对于面向消息的套接字,从第一个排队的消息中提取数据,最大大小为指定的缓冲区大小。 如果数据报或消息大于指定的缓冲区,则用数据报的第一部分填充缓冲区, recvfrom 将生成错误 WSAEMSGSIZE。 例如,对于不可靠的协议 (,UDP) 会丢失多余的数据。 对于 UDP,如果收到的数据包不包含 (空) 的数据,则 来自 recvfrom 函数的返回值为零。
如果 from 参数不为零,并且套接字不面向连接, (类型SOCK_DGRAM例如) ,则发送数据的对等方的网络地址将复制到相应的 sockaddr 结构。 fromlen 指向的值初始化为此结构的大小,并在返回时进行修改,以指示存储在 sockaddr 结构中的地址的实际大小。
如果套接字上没有可用的传入数据, 则 recvfrom 函数会根据为 WSARecv 定义的阻止规则阻止并等待数据到达,除非套接字为非阻止,否则不会设置MSG_PARTIAL标志。 在这种情况下,返回值 SOCKET_ERROR,错误代码设置为 WSAEWOULDBLOCK。 select、WSAAsyncSelect 或 WSAEventSelect 可用于确定何时到达更多数据。
如果套接字面向连接,并且远程端已正常关闭连接,则对 recvfrom 的调用将立即完成,并且接收了零个字节。 如果连接已重置 ,则 recvfrom 将失败,并显示 错误 WSAECONNRESET。
flags 参数可用于影响为关联套接字指定的选项之外的函数调用行为。 此函数的语义由套接字选项和 flags 参数确定。 后者是使用以下任一值的按位 OR 运算符构造的。
值 | 含义 |
---|---|
MSG_PEEK | 查看传入数据。 数据会复制到缓冲区中,但不会从输入队列中删除。 |
MSG_OOB | 处理带外 (OOB) 数据。 |
示例代码
以下示例演示如何使用 recvfrom 函数。#ifndef UNICODE
#define UNICODE
#endif
#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")
int main()
{
int iResult = 0;
WSADATA wsaData;
SOCKET RecvSocket;
struct sockaddr_in RecvAddr;
unsigned short Port = 27015;
char RecvBuf[1024];
int BufLen = 1024;
struct sockaddr_in SenderAddr;
int SenderAddrSize = sizeof (SenderAddr);
//-----------------------------------------------
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != NO_ERROR) {
wprintf(L"WSAStartup failed with error %d\n", iResult);
return 1;
}
//-----------------------------------------------
// Create a receiver socket to receive datagrams
RecvSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (RecvSocket == INVALID_SOCKET) {
wprintf(L"socket failed with error %d\n", WSAGetLastError());
return 1;
}
//-----------------------------------------------
// Bind the socket to any address and the specified port.
RecvAddr.sin_family = AF_INET;
RecvAddr.sin_port = htons(Port);
RecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
iResult = bind(RecvSocket, (SOCKADDR *) & RecvAddr, sizeof (RecvAddr));
if (iResult != 0) {
wprintf(L"bind failed with error %d\n", WSAGetLastError());
return 1;
}
//-----------------------------------------------
// Call the recvfrom function to receive datagrams
// on the bound socket.
wprintf(L"Receiving datagrams...\n");
iResult = recvfrom(RecvSocket,
RecvBuf, BufLen, 0, (SOCKADDR *) & SenderAddr, &SenderAddrSize);
if (iResult == SOCKET_ERROR) {
wprintf(L"recvfrom failed with error %d\n", WSAGetLastError());
}
//-----------------------------------------------
// Close the socket when finished receiving datagrams
wprintf(L"Finished receiving. Closing socket.\n");
iResult = closesocket(RecvSocket);
if (iResult == SOCKET_ERROR) {
wprintf(L"closesocket failed with error %d\n", WSAGetLastError());
return 1;
}
//-----------------------------------------------
// Clean up and exit.
wprintf(L"Exiting.\n");
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 |
标头 | winsock.h (包括 Winsock2.h) |
Library | Ws2_32.lib |
DLL | Ws2_32.dll |