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>