RECV - Linux手册页

时间:2019-08-20 17:59:14  来源:igfitidea点击:

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

名称

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

语法

#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);

说明

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_ORIGIN_NONE    0
#define SO_EE_ORIGIN_LOCAL   1
#define SO_EE_ORIGIN_ICMP    2
#define SO_EE_ORIGIN_ICMP6   3

struct sock_extended_err
{
    uint32_t ee_errno;   /* Error number */
    uint8_t  ee_origin;  /* Where the error originated */
    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_origin是错误起源的原始代码。其他字段是特定于协议的。宏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;  /* Originating 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
表示未收到任何数据,但套接字错误队列中出现扩展错误。

返回值

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

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

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

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

错误说明

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

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

遵循规范

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

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

备注

如果零长度数据报待处理,则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),该系统调用可用于在单个调用中接收多个数据报。

示例

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

另外参见

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)

出版信息

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