sendmsg() 是 POSIX 标准中一个高级套接字发送函数,属于系统调用(由操作系统内核实现),定义在 <sys/socket.h> 头文件中。它的核心特点是支持复杂消息结构,不仅能发送常规数据,还能附加控制信息(如辅助数据、IP 选项等),适用于 TCP、UDP 等多种协议,功能比 send()/sendto() 更灵活。
一、函数原型
#include <sys/socket.h>ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
二、参数详解
1. sockfd(套接字描述符)
类型:int
作用:已创建的套接字描述符(如通过 socket() 创建的 TCP 或 UDP 套接字)。
要求:若为 UDP 等无连接协议,需在 msg 中指定目标地址;若为 TCP 等已连接协议(通过 connect() 绑定),可省略地址。
2. msg(消息结构,核心参数)
类型:const struct msghdr *
作用:指向 struct msghdr 结构体,该结构体封装了发送的数据、目标地址、控制信息等所有与消息相关的内容。
struct msghdr 结构体定义如下(不同系统可能略有差异,以 Linux 为例):
struct msghdr {void *msg_name; // 目标地址(可选,仅无连接协议需要)socklen_t msg_namelen; // 目标地址长度struct iovec *msg_iov; // 数据缓冲区数组(常规数据)size_t msg_iovlen; // 数据缓冲区数量void *msg_control; // 控制信息缓冲区(辅助数据)size_t msg_controllen; // 控制信息缓冲区大小int msg_flags; // 接收时的标志(发送时忽略)
};
各字段详解:
辅助结构:struct iovec(数据缓冲区)
-msg_iov 指向的 struct iovec 数组用于定义常规数据的缓冲区,结构如下:
struct iovec {void *iov_base; // 缓冲区起始地址(数据存放的内存位置)size_t iov_len; // 缓冲区长度(要发送的字节数)
};
- 作用:支持 “分散发送”—— 将多个不连续的缓冲区数据合并成一个消息发送(无需先手动拼接)。
辅助结构:控制信息(cmsghdr)
msg_control 指向的控制信息缓冲区用于存储辅助数据,格式由 struct cmsghdr 定义:
struct cmsghdr {size_t cmsg_len; // 控制信息的总长度(含头部和数据)int cmsg_level; // 协议级别(如 SOL_SOCKET、IPPROTO_IP)int cmsg_type; // 控制信息类型(如 SCM_RIGHTS 表示传递文件描述符)// 数据部分(紧跟在结构体后,需通过宏访问)
};
- 常见用途:
通过 Unix 域套接字传递文件描述符(SCM_RIGHTS)。
设置 IP 选项(如 IP_TTL 控制生存时间)。
传递网络接口索引(绑定特定网卡发送)。
3. flags(发送标志)
- 类型:int
- 作用:控制发送行为,与 send()/sendto() 的 flags 参数相同,可组合使用(通过按位或 |)。
- 常见取值:
0:默认行为。
MSG_DONTROUTE:不经过路由表,仅在本地网络发送。
MSG_DONTWAIT:非阻塞发送(若套接字为阻塞模式,临时转为非阻塞)。
MSG_NOSIGNAL:发送 TCP 数据时,若对方已关闭连接,不产生 SIGPIPE 信号。
三、返回值
成功:返回实际发送的字节数(仅计算 msg_iov 中的常规数据,不包含控制信息)。
失败:返回 -1,并设置 errno 表示错误原因(如 EBADF 表示套接字无效,EINVAL 表示参数错误)。
四、使用场景与示例
sendmsg() 因支持控制信息和分散发送,适合以下场景:
1.传递辅助数据(如文件描述符、IP 选项)。
2.发送分散在多个缓冲区的数据(避免手动拼接)。
4.1 用 sendmsg() 实现 UDP 数据发送,功能等同于 sendto():
#include <stdio.h>
#include <sys/socket.h>