侧边栏壁纸
博主头像
noerror

虚灵不寐,众理具而万事出。

  • 累计撰写 238 篇文章
  • 累计创建 9 个标签
  • 累计收到 2 条评论
标签搜索

目 录CONTENT

文章目录

cmsg函数用法详解

noerror
2022-10-14 / 0 评论 / 0 点赞 / 34 阅读 / 1,276 字 / 正在检测是否收录...

cmsg函数用法详解

cmsg函数简介

  • 头文件包含
#include <sys/socket.h>
  • 函数定义
struct cmsghdr *CMSG_FIRSTHDR(struct msghdr * msgh );
struct cmsghdr *CMSG_NXTHDR(struct msghdr * msgh ,
size_t CMSG_ALIGN(size_t  length );
size_t CMSG_SPACE(size_t  length );
size_t CMSG_LEN(size_t  length );
unsigned char *CMSG_DATA(struct cmsghdr * cmsg );

cmsg函数常见使用错误

  • 编译错误
    warning: implicit declaration of function ‘cmsg’ [-Wimplicit-function-declaration]
    解决办法:包含头文件
#include <sys/socket.h>

cmsg函数详细描述

这些宏用于创建和访问不属于套接字有效负载的控制消息(也称为辅助数据)。此控制信息可能包括接收数据包的接口、各种很少使用的头字段、扩展的错误描述、一组文件描述符或UNIX凭据。例如,控制消息可用于发送额外的标头字段,如IP选项。辅助数据通过调用sendmsg (2)发送,通过调用recvmsg (2)接收,更多信息请参见它们的手册页。
辅助数据是带有附加数据的cmsghdr结构序列。有关可用的控制消息类型,请参见特定的协议手册页。每个套接字允许的最大辅助缓冲区大小可以使用/proc/sys/net/core/optmem_max ;来设置(请参阅socket (7)
cmsghdr结构定义如下:

struct cmsghdr {
   size_t cmsg_len;    /* Data byte count, including header
                          (type is socklen_t in POSIX) */
   int    cmsg_level;  /* Originating protocol */
   int    cmsg_type;   /* Protocol-specific type */
/* followed by
  unsigned char cmsg_data[]; */
};

永远不应该直接访问cmsghdr结构的序列。相反,只使用以下宏:

  • CMSG_FIRSTHDR ()返回一个指针,指向与传递的msghdr 相关联的辅助数据缓冲区中的第一个cmsghdr,如果缓冲区中没有足够的空间容纳cmsghdr,则返回NULL。
  • CMSG_NXTHDR ()在传递的cmsghdr 之后返回下一个有效的cmsghdr,当缓冲区中没有足够的空间时,它返回NULL。当初始化一个将包含一系列cmsghdr结构的缓冲区时(例如,要与sendmsg (2))一起发送),该缓冲区应首先为零初始化,以确保CMSG_NXTHDR ()的正确操作
  • CMSG_ALIGN ()给定一个长度,返回它,包括所需的对齐方式。这是一个常量表达式。
  • CMSG_SPACE ()返回具有传递数据长度的有效负载的辅助元素所占的字节数。这是一个常量表达式。
  • CMSG_DATA ()返回一个指向cmsghdr 的数据部分的指针,不能假定所返回的指针被适当地对齐以访问任意有效负载数据类型。应用程序不应将其强制转换为与有效负载匹配的指针类型,而应使用memcpy (3)将数据复制到适当声明的对象或从该对象复制数据。
  • CMSG_LEN ()返回要存储在cmsghdr结构的cmsg_len成员中的值,同时考虑任何必要的对齐方式。它以数据长度作为参数。这是一个常量表达式。

要创建辅助数据,首先用控制消息缓冲区的长度初始化msghdr的msg_controllen成员。在msghdr上使用CMSG_FIRSTHDR ()获得第一个控制消息,在CMSG_NXTHDR ()获得所有后续消息。在每个控制消息中,初始化cmsg_len(CMSG_LEN ())其他cmsghdr报头字段,数据部分使用CMSG_DATA ()最后,msghdr0的msg_controllen字段应设置为缓冲区中所有控制消息长度的CMSG_SPACE ()之和。有关msghdr 的更多信息,请参见recvmsg (2)

cmsg函数其他说明

为了可移植性,应该只使用这里描述的宏来访问辅助数据。CMSG_ALIGN ()是一个Linux扩展,不应该在可移植程序中使用。
在Linux中,CMSG_LEN ()、CMSG_DATA ()和CMSG_ALIGN ()是常量表达式(假设它们的参数是常量),这意味着这些值可以用来声明全局变量的大小。然而,这可能不是可移植的。

cmsg函数使用举例

以下代码在接收到的辅助缓冲区中查找 IP_TTL 选项:

struct msghdr msgh;
struct cmsghdr *cmsg;
int received_ttl;

/* Receive auxiliary data in msgh */

for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL;
       cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
   if (cmsg\->cmsg_level == IPPROTO_IP
           && cmsg\->cmsg_type == IP_TTL) {
       memcpy(&receive_ttl, CMSG_DATA(cmsg), sizeof(received_ttl));
       break;
   }
}

if (cmsg == NULL) {
   /* Error: IP_TTL not enabled or small buffer or I/O error */
}

下面的代码使用SCM_RIGHTS :通过UNIX域套接字传递文件描述符数组

struct msghdr msg = { 0 };
struct cmsghdr *cmsg;
int myfds[NUM_FD];  /* Contains the file descriptors to pass */
char iobuf[1];
struct iovec io = {
   .iov_base = iobuf,
   .iov_len = sizeof(iobuf)
};
union {         /* Ancillary data buffer, wrapped in a union
                  in order to ensure it is suitably aligned */
   char buf[CMSG_SPACE(sizeof(myfds))];
   struct cmsghdr align;
} u;

msg.msg_iov = &io;
msg.msg_iovlen = 1;
msg.msg_control = u.buf;
msg.msg_controllen = sizeof(u.buf);
cmsg = CMSG_FIRSTHDR(&msg);
cmsg\->cmsg_level = SOL_SOCKET;
cmsg\->cmsg_type = SCM_RIGHTS;
cmsg\->cmsg_len = CMSG_LEN(sizeof(myfds));
memcpy(CMSG_DATA(cmsg), myfds, sizeof(myfds));
0

评论区