简介struct cmsghdr结构

简介struct cmsghdr结构

在阅读《Linux高性能服务器编程》的时候,遇到了一些结构体不太记得住 记录一下 参考链接:https://blog.csdn.net/shisiye15/article/details/7762609

我们需要注意以下几点: cmsg_len与CMSG_LEN()宏值所显示的长度相同。 CMSG_SPACE()宏可以计算一个附属数据对象的所必需的空白。 msg_controllen是CMSG_SPACE()长度之后,并且为每一个附属数据对象进行计算。 控制信息头部本身由下面的C结构定义:

struct cmsghdr {

socklen_t cmsg_len;

int cmsg_level;

int cmsg_type;

u_char cmsg_data[];

};

其成员描述如下: cmsg_len 附属数据的字节计数,这包含结构头的尺寸。这个值是由CMSG_LEN()宏计算的。 cmsg_level 这个值表明了原始的协议级别(例如,SOL_SOCKET)。 cmsg_type 这个值表明了控制信息类型(例如,SCM_RIGHTS)。 cmsg_data 这个成员并不实际存在。他用来指明实际的额外附属数据所在的位置。(柔性数组) 这一章所用的例子程序只使用SOL_SOCKET的cmsg_level值。这一章我们感兴趣的控制信息类型如下(cmsg_level=SOL_SOCKET): cmsg_level 描述 SCM_RIGHTS 附属数据对象是一个文件描述符 SCM_CREDENTIALS 附属数据对象是一个包含证书信息的结构 简介cmsg(3)宏 由于附属数据结构的复杂性,Linux系统提供了一系列的C宏来简化我们的工作。另外,这些宏可以在不同的UNIX平台之间进行移植,并且采取了一些措施来防止将来的改变。这些宏是由cmsg(3)的man手册页来进行描述的,其概要如下:

#include

struct cmsghdr *CMSG_FIRSTHDR(struct msghdr *msgh);

struct cmsghdr *CMSG_NXTHDR(struct msghdr *msgh, struct cmsghdr *cmsg);

size_t CMSG_ALIGN(size_t length);

size_t CMSG_SPACE(size_t length);

size_t CMSG_LEN(size_t length);

void *CMSG_DATA(struct cmsghdr *cmsg);

CMSG_LEN()宏 这个宏接受我们希望放置在附属数据缓冲区中的对象尺寸作为输入参数。如果我们回顾一个我们前面的介绍,我们就会发现这个宏会计算cmsghdr头结构加上所需要的填充字符的字节长度。这个值用来设置cmsghdr对象的cmsg_len成员。 下面的例子演示了如果附属数据是一个文件描述符,我们应如何来计算cmsg_len成员的值:

int fd; /* File descriptor */

printf("cmsg_len = %d/n",CMSG_LEN(sizeof fd));

CMSG_SPACE()宏 这个宏用来计算附属数据以及其头部所需的总空白。尽管CMSG_LEN()宏计算了一个相似的长度,CMSG_LEN()值并不包括可能的结尾的填充字符。CMSG_SPACE()宏对于确定所需的缓冲区尺寸是十分有用的,如下面的示例代码所示:

int fd; /* File Descriptor */

char abuf[CMSG_SPACE(sizeof fd)];

这个例子在abuf[]中声明了足够的缓冲区空间来存放头部,填充字节以及附属数据本身,和最后的填充字节。如果在缓冲区中有多个附属数据对象,一定要同时添加多个CMSG_SPACE()宏调用来得到所需的总空间。 CMSG_DATA()宏 这个宏接受一个指向cmsghdr结构的指针。返回的指针值指向跟随在头部以及填充字节之后的附属数据的第一个字节(如果存在)。如果指针mptr指向一个描述文件描述符的可用的附属数据信息头部,这个文件描述符可以用下面的代码来得到: 这里用了强制转换,本来指向char

struct cmsgptr *mptr;

int fd; /* File Descriptor */

. . .

fd = *(int *)CMSG_DATA(mptr);

CMSG_ALIGN()宏 这是一个Linux扩展宏,而不是Posix.1g标准的一部分。指定一个字节长度作为输入,这个宏会计算一个新的长度,这个新长度包括为了维护对齐所需要的额外的填充字节。 CMSG_FIRSTHDR()宏 这个宏用于返回一个指向附属数据缓冲区内的第一个附属对象的struct cmsghdr指针。输入值为是指向struct msghdr结构的指针(不要与struct cmsghdr相混淆)。 这个宏会估计msghdr的成员msg_control与msg_controllen来确定在缓冲区中是否存在附属对象。然后,他会计算返回的指针。 **如果不存在附属数据对象则返回的指针值为NULL。否则,这个指针会指向存在的第一个struct cmsghdr。**这个宏用在一个for循环的开始处,来开始在附属数据对象中遍历。 CMSG_NXTHDR()宏 这个用于返回下一个附属数据对象的struct cmsghdr指针。这个宏会接受两个输入参数: 指向struct msghdr结构的指针 指向当前struct cmsghdr的指针 如果没有下一个附属数据对象,这个宏就会返回NULL。 遍历附属数据: 当接收到一个附属数据时,我们可以使用CMSG_FIRSTHDR() CMSG_NXTHDR()宏来在附属数据对象中进行遍历。下面的示例代码显示了for循环的通常格式以及宏的相应用法:

struct msghdr msgh; /* Message Hdr */

struct cmsghdr *cmsg;0 /*Ptr to ancillary hdr */

int *fd_ptr; /* Ptr to file descript.*/

int received_fd; /* The file descriptor */

for ( cmsg=CMSG_FIRSTHDR(&msgh); cmsg!=NULL; cmsg=CMSG_NXTHDR(&msgh,cmsg) ) {

if ( cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS ) {

fd_ptr = (int *) CMSG_DATA(cmsg);

received_fd = *fd_ptr;

break;

}

}

if ( cmsg == NULL ) {

/* Error: No file descriptor recv'd */

}

创建附属数据 要发送一个文件描述符的进程必须使用正确的格式化数据来创建一个附属数据缓冲区。下面的代码展示的通常的创建过程:

/* Message header */

struct msghdr msg;

/* Ptr to ancillary hdr */

struct cmsghdr *cmsg;

/* File descriptor to send */

int fd;

/* Anc. buf */

char buf[CMSG_SPACE(sizeof fd)];

/* Ptr to file descriptor */

int *fd_ptr;

msg.msg_control = buf;

msg.msg_controllen = sizeof buf;

cmsg = CMSG_FIRSTHDR(&msg);

cmsg->cmsg_level = SOL_SOCKET;

cmsg->cmsg_type = SCM_RIGHTS;

cmsg->cmsg_len = CMSG_LEN(sizeof fd);

/* Initialize the payload: */

fd_ptr = (int *)CMSG_DATA(cmsg);

*fd_ptr = fd;

/*

* Sum of the length of all control

* messages in the buffer:

*/

msg.msg_controllen = cmsg->cmsg_len;

相关推荐

4亿播放的“马桶人”动画带火了一众IP游戏,这会是短剧出海的新思路吗?
GB(强制性国家标准)以及GB\T(推荐性国家标准)文件免费查询、浏览、下载方法
滕王阁序
365体育投注3

滕王阁序

📅 07-11 👁️ 1602
Android Activity 生成 View 过程
365体育投注3

Android Activity 生成 View 过程

📅 06-28 👁️ 8703
估值分析
365足球平台入口

估值分析

📅 07-10 👁️ 1412
交强险车损能赔多少钱?交强险自己车损能报吗
谁知道365bet网址

交强险车损能赔多少钱?交强险自己车损能报吗

📅 07-29 👁️ 4319
哔哩哔哩视频如何收费?详细解读B站收费模式,带你玩转会员与大会员
虹彩六號:圍攻行動
谁知道365bet网址

虹彩六號:圍攻行動

📅 07-24 👁️ 6175
极盗车神(安塞尔·艾尔高特、莉莉·詹姆斯主演电影)什么时候上映