附属信息可以包括0,1,或是更多的单独附属数据对象。在每一个对象之前都有一个struct
cmsghdr结构。头部之后是填充字节,然后是对象本身。最后,附属数据对象之后,下一个cmsghdr之前也许要有更多的填充字节。在这一章,我们将
要关注的附属数据对象是文件描述符与证书结构。
下图显示了一个包含附属数据的缓冲区是如何组织的。
我们需要注意以下几点:
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指向一个描述文件描述符的可用的附属数据信息头部,这个文件描述符可以用下面的代码来得到:
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 */
}
创建附属数据
要发送一个文件描述符的进程必须使用正确的格式化数据来创建一个附属数据缓冲区。下面的代码展示的通常的创建过程:
struct msghdr msg;            /* Message header */
struct cmsghdr *cmsg; /* Ptr to ancillary hdr */
int fd;              /* File descriptor to send */
char buf[CMSG_SPACE(sizeof fd)]; /* Anc. buf */
int *fd_ptr;           /* Ptr to file descriptor */
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;

简介struct cmsghdr结构相关推荐

  1. struct sched_param结构体的运用以及线程属性简单记录

    一.struct sched_param结构体 #include <sched.h> #define sched_ss_low_priority __ss_un.__ss.__ss_low ...

  2. struct timeval结构体

    struct timeval结构体在time.h中的定义为: struct timeval { __time_t tv_sec;        /* Seconds. */ __suseconds_t ...

  3. linux sock结构体,struct socket结构体详解

    在内核中为什么要有struct socket结构体呢? struct socket结构体的作用是什么? 下面这个图,我觉得可以回答以上两个问题.  由这个图可知,内核中的进程可以通过使用struct ...

  4. C/C++结构体struct 与结构体数组和枚举型enum的结合使用

    C/C++结构体struct 与结构体数组和枚举型enum的结合使用 #include "stdafx.h" #include <string> #include &l ...

  5. struct ethhdr结构体详解

        在linux系统中,使用struct ethhdr结构体来表示以太网帧的头部.这个struct ethhdr结构体位于#include<linux/if_ether.h>之中. # ...

  6. struct timeval结构体 以及 gettimeofday()函数

    一.struct timeval结构体 struct timeval结构体在time.h中的定义为: struct timeval { __time_t tv_sec;        /* Secon ...

  7. struct device结构体(2.6.23)

    struct device结构体(2.6.23)   一.定义: linux/include/linux/device.h struct device {         struct klist   ...

  8. [matlab]使用struct创建结构体

    [matlab]使用struct创建结构体 语法: struct(域名1,属性值1,域名2,属性值2,.....) 我们具体看看结构体怎么使用: >> person(1)=struct(' ...

  9. struct sk_buff结构体详解

    struct sk_buff是linux网络系统中的核心结构体,linux网络中的所有数据包的封装以及解封装都是在这个结构体的基础上进行. 1 2 3 4 5 6 7 8 9 10 11 12 13 ...

最新文章

  1. java cpu 监控工具_Java自带的GUI性能监控工具Jconsole以及JisualVM简介
  2. Possible missing firmware /lib/firmware/i915/bxt_guc_ver8_7.bin for module i915
  3. vector容器中清空元素(但原来的元素还在)
  4. android显示绘图动画,Android自定义View绘图实现渐隐动画
  5. python getopterror_python3 getopt用法
  6. AIX HACMP集群切换测试实际案例解析
  7. 自定义注解完成数据库切库
  8. RTX游戏本助你玩转一线游戏 畅快过大年
  9. MVC学习五:Razor布局页面 _ViewStart.cshtml
  10. 数数苹果手机中的不科学
  11. python单元测试用例_Python单元测试与测试用例简析
  12. Interesting卡常数
  13. 复联4定档 4.24——十一年21部漫威电影,用数据为你梳理口碑、票房、主演最佳......
  14. 借用 AWS 服务 CodePipeling + ECS 实现蓝绿发布 (awscli)
  15. Java 汉字 转 拼音/首字母
  16. 数据分析实战(三):美国1800~2010年婴儿名字
  17. 免校准的电量计量芯片_技术 | 免校准电能计量芯片,让家电智能化更简单
  18. 昊鼎王五:网站(前端)如何调用美图秀秀?
  19. android lint 安全检测,Android Lint检查
  20. 2021年6月4日大学化学无机原理(13)原子的电子层结构

热门文章

  1. Java按照时间顺序从hbase中读出数据
  2. Weblogic部署web项目获取项目根目录为null
  3. SOAR SQL进行优化和改写的自动化工具
  4. Python socket的客户端
  5. Dell Venue 8 Pro启动盘UEFI模式32位启动,备份系统
  6. 微信公众平台前端开发技巧分享
  7. sqlite3API函数
  8. (转)在Total Commander下使用SVN
  9. Linux系统下提升进程优先级的办法
  10. f2py支持在fortran语言中调用其他Fortran函数或C代码或Python代码