TCP/IP函数——sendmsg

发布于:2025-09-06 ⋅ 阅读:(13) ⋅ 点赞:(0)

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>

网站公告

今日签到

点亮在社区的每一天
去签到