说明

recv(),recvfrom()和recvmsg()调用用于从套接字接收消息。它们可用于在无连接和面向连接的套接字上接收数据。此页面首先描述所有三个系统调用的共同功能,然后描述调用之间的区别。

recv()和read(2)之间的唯一区别是标志的存在。使用零标志参数时,recv()通常等效于read(2)(但请参阅注意)。还有,下面的电话

recv(sockfd,buf,len,flags);

相当于

recvfrom(sockfd,buf,len,flags,NULL,NULL);

成功完成后,这三个调用都将返回消息的长度。如果消息太长而无法容纳在提供的缓冲区中,则多余的字节可能会被丢弃,具体取决于接收消息的套接字类型。

如果套接字上没有可用的消息,则接收调用将等待消息到达,除非套接字是非阻塞的(请参阅fcntl(2)),在这种情况下,将返回值-1且外部变量errno设置为EAGAIN或EWOULDBLOCK。接收呼叫通常返回不超过请求数量的所有可用数据,而不是等待收到请求的全部数量。

应用程序可以使用select(2),poll(2)或epoll(7)来确定何时有更多数据到达套接字。

The flags argument

flags参数是通过对以下一个或多个值进行"或"运算形成的:

MSG_CMSG_CLOEXEC(recvmsg() only; since Linux 2.6.23)
使用SCM_RIGHTS操作(在unix(7)中描述)为通过UNIX域文件描述符接收的文件描述符设置close-on-exec标志。出于与open(2)的O_CLOEXEC标志相同的原因,此标志很有用。
MSG_DONTWAIT(since Linux 2.2)
启用非阻塞操作;如果操作将阻止,则调用失败,并显示错误EAGAIN或EWOULDBLOCK。这提供了与设置O_NONBLOCK标志类似的行为(通过fcntl(2)F_SETFL操作),但不同之处在于MSG_DONTWAIT是按调用的选项,而O_NONBLOCK是打开文件说明中的设置(请参见open(2)),这将影响调用进程中的所有线程以及保存引用同一打开文件描述的文件描述符的其他进程。
MSG_ERRQUEUE(since Linux 2.2)
该标志指定应该从套接字错误队列中接收排队的错误。该错误会在辅助消息中传递,其类型取决于协议(对于IPv4 IP_RECVERR)。用户应提供足够大小的缓冲区。有关更多信息,请参见cmsg(3)和ip(7)。导致错误的原始数据包的有效负载通过msg_iovec作为普通数据传递。导致错误的数据报的原始目标地址通过msg_name提供。
该错误在sock_extended_err结构中提供:
#define SO_EE_ORoirN_NONE    0
#define SO_EE_ORoirN_LOCAL   1
#define SO_EE_ORoirN_ICMP    2
#define SO_EE_ORoirN_ICMP6   3

struct sock_extended_err
{
    uint32_t ee_errno;   /* Error number */
    uint8_t  ee_oroirn;  /* Where the error oroirnated */
    uint8_t  ee_type;    /* Type */
    uint8_t  ee_code;    /* Code */
    uint8_t  ee_pad;     /* Padding */
    uint32_t ee_info;    /* Additional information */
    uint32_t ee_data;    /* Other data */
    /* More data may follow */
};

struct sockaddr *SO_EE_OFFENDER(struct sock_extended_err *);
ee_errno包含排队的错误的错误号。 ee_oroirn是错误起源的原始代码。其他字段是特定于协议的。宏SOCK_EE_OFFENDER返回一个指向网络对象地址的指针,该地址的错误源于给定辅助消息的指针。如果该地址未知,则sockaddr的sa_family成员包含AF_UNSPEC,并且sockaddr的其他字段未定义。导致错误的数据包的有效负载作为普通数据传递。
对于本地错误,不会传递任何地址(可以使用cmsghdr的cmsg_len成员检查该地址)。对于错误接收,在msghdr中设置MSG_ERRQUEUE标志。传递错误后,将根据下一个排队的错误重新生成挂起的套接字错误,并将在下一个套接字操作中传递该错误。
MSG_OOB
该标志请求接收正常数据流中不会接收到的带外数据。某些协议将加速数据放置在普通数据队列的开头,因此该标志不能与此类协议一起使用。
MSG_PEEK
此标志使接收操作从接收队列的开头返回数据,而不会从队列中删除该数据。因此,后续的接收呼叫将返回相同的数据。
MSG_TRUNC(since Linux 2.2)
对于原始(AF_PACKET),Internet数据报(自Linux 2.4.27 / 2.6.8起),netlink(自Linux 2.6.22起)和UNIX数据报(自Linux 3.4起):返回数据包或数据报的实际长度,甚至比传递的缓冲区长的时间。
要与Internet流套接字一起使用,请参见tcp(7)。
MSG_WAITALL(since Linux 2.2)
该标志请求操作块,直到满足完整请求为止。但是,如果捕获到信号,发生错误或断开连接,或者下一个要接收的数据与返回的数据类型不同,则呼叫返回的数据仍可能比请求的少。该标志对数据报套接字无效。

recvfrom()

recvfrom()将接收到的消息放入缓冲区buf。调用者必须以len为单位指定缓冲区的大小。

如果src_addr不为NULL,并且基础协议提供了消息的源地址,则该源地址将放置在src_addr指向的缓冲区中。在这种情况下,addrlen是一个值结果参数。在调用之前,应将其初始化为与src_addr关联的缓冲区的大小。返回时,addrlen更新为包含源地址的实际大小。如果提供的缓冲区太小,返回的地址将被截断。在这种情况下,addrlen将返回一个大于提供给调用的值。

如果调用方对源地址不感兴趣,则应将src_addr和addrlen指定为NULL。

recv()

recv()调用通常仅在连接的套接字上使用(请参阅connect(2))。它等效于调用:

recvfrom(fd,buf,len,flags,NULL,0);

recvmsg()

recvmsg()调用使用msghdr结构来最大程度减少直接提供的参数的数量。该结构的定义如下:

struct iovec {                    /* Scatter/gather array items */
    void  *iov_base;              /* Starting address */
    size_t iov_len;               /* Number of bytes to transfer */
};

struct msghdr {
    void         *msg_name;       /* Optional address */
    socklen_t     msg_namelen;    /* Size of address */
    struct iovec *msg_iov;        /* Scatter/gather array */
    size_t        msg_iovlen;     /* # elements in msg_iov */
    void         *msg_control;    /* Ancillary data, see below */
    size_t        msg_controllen; /* Ancillary data buffer len */
    int           msg_flags;      /* Flags on received message */
};

msg_name字段指向调用者分配的缓冲区,如果套接字未连接,则该缓冲区用于返回源地址。在此调用之前,调用者应将msg_namelen设置为此缓冲区的大小;成功调用返回后,msg_namelen将包含返回地址的长度。如果应用程序不需要知道源地址,则可以将msg_name指定为NULL。

readv(2)中所述,字段msg_iov和msg_iovlen描述了分散收集位置。

长度为msg_controllen的字段msg_control指向其他协议控制相关消息或其他辅助数据的缓冲区。调用recvmsg()时,msg_controllen应包含msg_control中可用缓冲区的长度;从成功调用返回后,它将包含控制消息序列的长度。

消息的形式为:

struct cmsghdr {
    size_t cmsg_len;    /* Data byte count, including header
                           (type is socklen_t in POSIX) */
    int    cmsg_level;  /* Oroirnating protocol */
    int    cmsg_type;   /* Protocol-specific type */
/* followed by
    unsigned char cmsg_data[]; */
};

辅助数据只能由cmsg(3)中定义的宏访问。

例如,Linux使用此辅助数据机制在UNIX域套接字上传递扩展的错误,IP选项或文件描述符。

msghdr中的msg_flags字段是在recvmsg()返回时设置的。它可以包含几个标志:

MSG_EOR
表示记录结束;返回的数据完成了一条记录(通常与SOCK_SEQPACKET类型的套接字一起使用)。
MSG_TRUNC
表示由于数据报大于提供的缓冲区,因此丢弃了数据报的尾部。
MSG_CTRUNC
表示由于缓冲区中没有足够的辅助数据空间而丢弃了某些控制数据。
MSG_OOB
返回表示已接收到加速或带外数据。
MSG_ERRQUEUE
表示未收到任何数据,但套接字错误队列中出现扩展错误。

遵循规范

POSIX.1-2001,POSIX.1-2008、4.4BSD(这些接口最早出现在4.2BSD中)。

POSIX.1仅描述了MSG_OOB,MSG_PEEK和MSG_WAITALL标志。

返回值

这些调用返回接收到的字节数,如果发生错误,则返回-1。如果发生错误,则将errno设置为指示错误。

当流套接字对等方执行有序关闭时,返回值将为0(传统的"文件结束"返回)。

各个域(例如UNIX和Internet域)中的数据报套接字允许零长度的数据报。收到这样的数据报后,返回值为0。

如果请求从流套接字接收的字节数为0,则也可能返回值0。

出版信息

这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/

名称

recv,recvfrom,recvmsg-从套接字接收消息

备注

如果零长度数据报待处理,则flags参数为零的read(2)和recv()提供不同的行为。在这种情况下,read(2)无效(数据报保持未决状态),而recv()使用未决的数据报。

socklen_t类型是POSIX发明的。另请参见accept(2)。

根据POSIX.1,msghdr结构的msg_controllen字段应键入socklen_t,msg_iovlen字段应键入int,但glibc当前都将其键入为size_t。

有关特定于Linux的系统调用的信息,请参见recvmmsg(2),该系统调用可用于在单个调用中接收多个数据报。

语法

#include <sys/types.h>

#include <sys/socket.h>

ssize_t recv(int sockfd, void *buf, size_t len, int flags);

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                 struct sockaddr *src_addr, socklen_t *addrlen);

ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

示例

getaddrinfo(3)中显示了使用recvfrom()的示例。

错误说明

这些是套接字层生成的一些标准错误。可能会产生其他错误并从底层协议模块中返回这些错误;请参阅他们的手册页。

EAGAINor EWOULDBLOCK
套接字被标记为非阻塞,并且接收操作将阻塞,或者已设置接收超时,并且超时在接收数据之前到期。 POSIX.1允许在这种情况下返回任一错误,并且不需要这些常量具有相同的值,因此可移植应用程序应检查这两种可能性。
EBADF
参数sockfd是无效的文件描述符。
ECONNREFUSED
远程主机拒绝允许网络连接(通常是因为它没有运行所请求的服务)。
EFAULT
接收缓冲区指针指向进程的地址空间之外。
EINTR
在任何数据可用之前,接收已通过信号传输中断;参见signal(7)。
EINVAL
传递了无效的参数。
ENOMEM
无法为recvmsg()分配内存。
ENOTCONN
套接字与面向连接的协议关联,并且尚未连接(请参阅connect(2)和accept(2))。
ENOTSOCK
文件描述符sockfd不引用套接字。
RECV - Linux手册页

Linux程序员手册 第2部分
更新日期: 2020-06-09

另外参见

fcntl(2),getsockopt(2),read(2),recvmmsg(2),select(2),shutdown(2),socket(2),cmsg(3),sockatmark(3),ip(7), ipv6(7),socket(7),tcp(7),udp(7),unix(7)

日期:2019-08-20 17:59:14 来源:oir作者:oir