recv, recvfrom, recvmsg - receive a message from a socket
recv()、recvfrom() 和 recvmsg() 调用用于从套接字接收消息。 它们可用于在UDP和TCP的套接字上接收数据。 本页首先介绍了所有三个系统调用的共同特点,然后介绍了调用之间的区别。
recv() 和 read(2) 之间的唯一区别是 flags 的存在。 使用零标志参数,recv() 通常等效于 read(2) (但请参阅 NOTES),且
recv(sockfd, buf, len, flags)
等价于
recvfrom(sockfd, buf, len, flags, NULL, NULL)
所有三个调用都在成功完成时返回消息的长度。 如果消息太长而无法放入提供的缓冲区,则 可能 会丢弃多余的字节,具体 取决于接收消息的套接字类型 ,显然TCP是不可能丢弃的。
如果套接字上没有可用消息,则接收调用将等待消息到达,除非套接字是非阻塞的(请参阅 fcntl(2)),在这种情况下,将返回值 -1 并将 errno 设置为 EAGAIN 或 EWOULDBLOCK。 recv_()调用通常会返回任何可用的数据,只要拿到数据就会立马返回,最多返回指定缓冲区大小的数据,但是并不会等待到让缓冲区满 ,除非设置了 MSG_WAITALL 标志,见下。
应用程序可以使用 select(2)、poll(2) 或 epoll(7) 来确定更多数据何时到达。
The flags argument is formed by ORing one or more of the following values:
ee_errno contains the errno number of the queued error. ee_origin is the origin code of where the error originated. The other fields are protocol-specific. The macro SOCK_EE_OFFENDER returns a pointer to the address of the network object where the error originated from given a pointer to the ancillary message. If this address is not known, the sa_family member of the sockaddr contains AF_UNSPEC and the other fields of the sockaddr are undefined. The payload of the packet that caused the error is passed as normal data.
For local errors, no address is passed (this can be checked with the cmsg_len member of the cmsghdr ). For error receives, the MSG_ERRQUEUE flag is set in the msghdr . After an error has been passed, the pending socket error is regenerated based on the next queued error and will be passed on the next socket operation.
recvfrom() 将接收到的消息放入缓冲区 buf 。 调用者必须在 len 中指定缓冲区的大小。
如果调用者希望拿到消息的原地址, 并且底层协议可以提供消息的源地址时,应将 src_addr 设置为指向用于接收消息原地址的缓冲区。 在这种情况下, addrlen 是一个 value-result 参数。 在调用之前,它应该被初始化为与 src_addr 关联的缓冲区的大小。 返回时,addrlen 被更新以包含源地址的实际大小。 如果提供的缓冲区太小,则截断返回的地址; 在这种情况下, addrlen 将返回一个大于提供给调用的值。
如果调用者对源地址不感兴趣,则应将 src_addr 和 addrlen 指定为 NULL。
ssize_t recv(int sockfd, void* buf, size_t len, int flags)
recv() 调用通常仅用于已连接的套接字(请参阅 connect(2))。 相当于调用:
recvfrom(fd, buf, len, flags, NULL, 0)
ssize_t recvmsg(int sockfd, struct msghdr* msg, int flags)
recvmsg() 调用使用 msghdr 结构来 最小化直接提供的参数数量 。 这个结构在 <sys/socket.h>中定义如下:
msg_name 字段指向调用者分配的缓冲区,如果套接字未连接( 特指UDP的服务端 ),则该缓冲区用于返回源地址。 调用者应在此调用之前将 msg_namelen 设置为此缓冲区的大小; 从成功调用返回后,msg_namelen 将包含返回地址的长度。 如果应用程序不需要知道源地址,可以将 msg_name 指定为 NULL。
The fields msg_iov and msg_iovlen describe scatter-gather locations, as discussed in readv(2).
需要注意的是 msg_iov 和 msg_iovlen 描述了一个 struct iovec 类型的数组, msg_iovlen 表示数组的元素个数,而struct iovec则是描述了一个缓冲区
字段 msg_control 指向用于其他协议控制相关消息或杂项辅助数据的缓冲区。 当recvmsg()被调用时, msg_controllen 为 msg_contro l中可用缓冲区的长度; 从成功调用返回时,它将被设置为控制消息序列的长度。
控制消息的格式为:
只能通过 cmsg(3) 中定义的宏访问辅助数据。
例如,Linux 使用这种辅助数据机制通过 UNIX 域套接字传递扩展错误、IP 选项或文件描述符。 有关在各种套接字域中使用辅助数据的更多信息,请参阅 unix(7) 和 ip(7)。
msghdr 中的 msg_flags 字段在 recvmsg() 返回时设置 。 它可以包含几个标志:
这些调用返回接收到的字节数,如果发生错误,则返回 -1。 如果发生错误,则设置 errno 以指示错误。
当流套接字对等端执行有序关闭(orderly shutdown)时,返回值将为 0(传统的“文件结束”返回)。
各种域(例如 UNIX 和 Internet 域)中的数据报套接字允许零长度数据报。 当收到这样的数据报时,返回值为 0。
如果从流套接字接收的请求字节数为 0,则也可能返回值 0。
这些是套接字层生成的一些标准错误。 底层协议模块可能会产生和返回额外的错误; 查看他们的手册页。
POSIX.1-2001, POSIX.1-2008, 4.4BSD (these interfaces first appeared in 4.2BSD).
POSIX.1 describes only the MSG_OOB, MSG_PEEK, and 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) 中显示了使用 recv() 的示例。
缓冲区与特定的块设备相关联,包括文件系统元数据的缓存以及页面跟踪。缓存只包含已停放的文件数据。也就是说,缓冲区记住目录中的内容、文件权限是什么,并跟踪从某个块设备中写入或读取到哪些内存。
缓存只包含文件本身的内容。
进行socket编程有时候可能需要修改下socket的接收缓冲区大小,这里可以使用 setsockopt 函数,但是如果需要修改的缓冲区很大(比如500MB),则还需要修改系统内核的TCP/IP参数,不然接收缓冲区大小会收到内核参数的限制,所以需要改两个地方。下面以把socket接收缓冲区修改为500MB说明一下要作的修改。《Linux就该这么学》
修改内核TCP/IP参数
在终端用sysctl命令修改socket最大缓冲区限制:
sudo sysctl -w net.core.rmem_max=5242880001
在代码中用setsockopt函数修改SO_RCVBUF选项
int recvbuff = 500*1024*1024
if(setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (const char*)&recvbuff, sizeof(int)) == -1)
printf("setsocket error\n")
else
printf("setsocket success\n")12345
以上两点,只改第1点,一个socket只会预留63个报文的接收缓冲;只改第2点,缓冲区大小会受到rmem_max的限制,如果需要的缓冲区很大的话,必须两点都改。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)