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 来检索特定的错误代码。

错误代码 含义
WSANOTINITIALISED
在使用此函数之前,必须成功调用 WSAStartup
WSAENETDOWN
网络子系统失败。
WSAEFAULT
buffrom 参数指向的缓冲区不在用户地址空间中,或者 fromlen 参数太小,无法容纳对等地址的源地址。
WSAEINTR
(阻止) 调用已通过 WSACancelBlockingCall 取消。
WSAEINPROGRESS
阻止 Windows Sockets 1.1 调用正在进行,或者服务提供程序仍在处理回调函数。
WSAEINVAL
套接字未绑定 绑定,或者指定了未知标志,或者为启用了SO_OOBINLINE的套接字指定了MSG_OOB,或者仅) len 为零或负数的字节流样式套接字 (。
WSAEISCONN
套接字已连接。 无论连接套接字是面向连接的还是无连接的套接字,都不允许使用此函数。
WSAENETRESET
对于数据报套接字,此错误显示生存时间已经过期。
WSAENOTSOCK
s 参数中的描述符不是套接字。
WSAEOPNOTSUPP
MSG_OOB已指定,但套接字不是流样式(如类型SOCK_STREAM),与此套接字关联的通信域中不支持 OOB 数据,或者套接字是单向的,仅支持发送操作。
WSAESHUTDOWN
套接字已关闭;在调用关闭后,无法套接字上重新显示SD_RECEIVE或SD_BOTH。
WSAEWOULDBLOCK
套接字标记为非阻塞, recvfrom 操作将阻止。
WSAEMSGSIZE
消息太大,无法容纳 到 buf 参数指向的缓冲区中,并且被截断。
WSAETIMEDOUT
由于网络故障或另一端的系统在未通知的情况下出现故障,连接已断开。
WSAECONNRESET
执行硬性或异常关闭的远程端重置了虚拟线路。 应用程序应关闭套接字;它不再可用。 在 UDP 数据报套接字上,此错误指示以前的发送操作导致 ICMP 端口无法访问 消息。

注解

recvfrom 函数读取已连接和未连接的套接字上的传入数据,并捕获从中发送数据的地址。 此函数通常用于无连接套接字。 套接字的本地地址必须是已知的。 对于服务器应用程序,这通常通过 绑定显式完成。 不建议对客户端应用程序进行显式绑定。 对于使用此函数的客户端应用程序,套接字可以通过 sendtoWSASendToWSAJoinLeaf 隐式绑定到本地地址。

对于面向流的套接字(如类型为 SOCK_STREAM 的套接字),对 recvfrom 的调用将返回当前可用的信息量(最大为指定缓冲区的大小)。 如果套接字已配置为内联接收 OOB 数据 (套接字选项SO_OOBINLINE) 且 OOB 数据尚未读取,则仅返回 OOB 数据。 应用程序可以使用 ioctlsocketWSAIoctlSIOCATMARK 命令来确定是否还有更多 OOB 数据需要读取。 对于面向连接的套接字,将忽略 fromfromlen 参数。

对于面向消息的套接字,从第一个排队的消息中提取数据,最大大小为指定的缓冲区大小。 如果数据报或消息大于指定的缓冲区,则用数据报的第一部分填充缓冲区, recvfrom 将生成错误 WSAEMSGSIZE。 例如,对于不可靠的协议 (,UDP) 会丢失多余的数据。 对于 UDP,如果收到的数据包不包含 (空) 的数据,则 来自 recvfrom 函数的返回值为零。

如果 from 参数不为零,并且套接字不面向连接, (类型SOCK_DGRAM例如) ,则发送数据的对等方的网络地址将复制到相应的 sockaddr 结构。 fromlen 指向的值初始化为此结构的大小,并在返回时进行修改,以指示存储在 sockaddr 结构中的地址的实际大小。

如果套接字上没有可用的传入数据, 则 recvfrom 函数会根据为 WSARecv 定义的阻止规则阻止并等待数据到达,除非套接字为非阻止,否则不会设置MSG_PARTIAL标志。 在这种情况下,返回值 SOCKET_ERROR,错误代码设置为 WSAEWOULDBLOCKselectWSAAsyncSelectWSAEventSelect 可用于确定何时到达更多数据。

如果套接字面向连接,并且远程端已正常关闭连接,则对 recvfrom 的调用将立即完成,并且接收了零个字节。 如果连接已重置 ,则 recvfrom 将失败,并显示 错误 WSAECONNRESET

flags 参数可用于影响为关联套接字指定的选项之外的函数调用行为。 此函数的语义由套接字选项和 flags 参数确定。 后者是使用以下任一值的按位 OR 运算符构造的。

含义
MSG_PEEK 查看传入数据。 数据会复制到缓冲区中,但不会从输入队列中删除。
MSG_OOB 处理带外 (OOB) 数据。
 
注意 发出阻止 Winsock 调用(如 recvfrom)时,Winsock 可能需要等待网络事件,然后调用才能完成。 在这种情况下,Winsock 执行可发出警报的等待, (在同一线程上计划的 APC) 异步过程调用可能会中断该等待。 在 APC 内发出另一个阻止 Winsock 调用,该调用中断了同一线程上正在进行的阻止 Winsock 调用将导致未定义的行为,并且 Winsock 客户端绝不能尝试。
 

示例代码

以下示例演示如何使用 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.1Windows 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

另请参阅

WSAAsyncSelect

WSAEventSelect

Winsock 函数

Winsock 参考

recv

send

sockaddr

socket