recvmsg函数的用法
recvmsg
是 Linux 网络编程中用于接收消息的高级系统调用,支持复杂数据结构和辅助数据的接收,适用于 TCP/UDP/UNIX 域套接字等场景。以下是其核心用法详解:
1. 函数原型与参数
#include <sys/socket.h>
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
-
sockfd
套接字描述符,需预先通过socket()
创建。 -
msg
指向msghdr
结构体的指针,用于存储消息的元数据和缓冲区信息(见下文详细解析)。 -
flags
控制接收行为的标志位(如MSG_PEEK
预览数据、MSG_WAITALL
阻塞直到数据满缓冲区)。
2. msghdr
结构体详解
struct msghdr {void *msg_name; // 可选:发送方地址(UDP 适用)socklen_t msg_namelen; // 地址长度struct iovec *msg_iov; // 分散/聚集 I/O 缓冲区数组size_t msg_iovlen; // 缓冲区数量void *msg_control; // 辅助数据(如文件描述符)size_t msg_controllen; // 辅助数据长度int msg_flags; // 接收消息的标志(输出参数)
};
关键字段说明
-
msg_iov
与msg_iovlen
支持多缓冲区接收数据(分散读取),通过iovec
结构体数组实现:struct iovec {void *iov_base; // 缓冲区起始地址size_t iov_len; // 缓冲区长度 };
buf1
和buf2
。 -
msg_control
与msg_controllen
用于接收辅助数据(如 UNIX 域套接字传递的文件描述符),需配合cmsghdr
结构体解析。
3. 典型应用场景
场景1:UDP 接收数据(带发送方地址)
struct sockaddr_in sender_addr;
struct msghdr msg = {0};
struct iovec iov;
char buf[1024];iov.iov_base = buf;
iov.iov_len = sizeof(buf);
msg.msg_name = &sender_addr;
msg.msg_namelen = sizeof(sender_addr);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;recvmsg(sockfd, &msg, 0); // 接收数据并获取发送方地址:ml-citation{ref="3,5" data="citationList"}
场景2:接收文件描述符(UNIX 域套接字)
struct msghdr msg = {0};
struct iovec iov;
char buf[8192];
int fd; // 接收的文件描述符// 辅助数据缓冲区(需对齐)
union {struct cmsghdr cm;char control[CMSG_SPACE(sizeof(int))];
} control_un;iov.iov_base = buf;
iov.iov_len = sizeof(buf);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = control_un.control;
msg.msg_controllen = sizeof(control_un.control);recvmsg(sockfd, &msg, 0);// 解析辅助数据获取文件描述符
struct cmsghdr *cmptr = CMSG_FIRSTHDR(&msg);
if (cmptr != NULL && cmptr->cmsg_type == SCM_RIGHTS) {fd = *((int *)CMSG_DATA(cmptr)); // 提取描述符
}
4. 标志位(flags
)详解
标志 | 作用 |
---|---|
MSG_PEEK | 预览数据但不从接收缓冲区移除(可重复读取) |
MSG_WAITALL | 阻塞直到请求的字节数全部接收(TCP 适用) |
MSG_DONTWAIT | 非阻塞模式,无数据时立即返回 EAGAIN |
MSG_TRUNC | 若数据被截断,通过 msg_flags 返回该标志(UDP 适用) |
5. 错误处理
- 返回值
成功时返回接收的字节数,失败返回-1
并设置errno
(如EAGAIN
、ECONNRESET
)。 -
msg_flags
输出
接收后可通过msg.msg_flags
检查附加标志(如MSG_TRUNC
、MSG_CTRUNC
)。
6. 性能与扩展性
- 优势
相比recv
/recvfrom
,recvmsg
支持多缓冲区和辅助数据,减少系统调用次数,提升效率。 - 限制
复杂参数需谨慎处理,如msg_control
缓冲区未对齐可能导致错误。
此函数广泛应用于高级网络编程(如 SCTP 协议、容器通信)和进程间文件描述符传递。