recvfrom 函数 (winsock2.h)

recvfrom 函数接收数据报,并存储源地址。

语法

int WSAAPI 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;
    sockaddr_in RecvAddr;

    unsigned short Port = 27015;

    char RecvBuf[1024];
    int BufLen = 1024;

    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
标头 winsock2.h (包括 Winsock2.h)
Library Ws2_32.lib
DLL Ws2_32.dll

另请参阅

WSAAsyncSelect

WSAEventSelect

Winsock 函数

Winsock 参考

recv

send

sockaddr

socket