RECV - Linux手册页
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/。