下表总结了辅助数据的主要用途。
辅助数据是由一个或多个辅助数据对象(ancillary data object)构成,每个对象都以一个 cmsghdr 结构开头。
#includestruct cmsghdr{ socklen_t cmsg_len; // length in bytes, includig this structure int cmsg_level; // originating protocol int cmsg_type; // protocol-specific type /* followed by unsigned char cmsg_data[] */ };
由 msg_control 指向的辅助数据必须为 cmsghdr 结构适当地对齐。下图展示了在一个控制缓冲区中出现 2 个辅助数据对象的例子(不是所有实现都支持在单个控制缓冲区中存放多个辅助数据对象)。
这里,msg_control 指向第一个辅助数据对象,msg_controllen 表示辅助数据的总长度。每个对象开头都是一个描述该对象的 cmsghdr 结构。在 cmsg_type 成员和实际数据之间可以有填充字节,从数据结尾处到下一个辅助数据对象之前也可以有填充字节。
为简化对辅助数据的处理,可以使用以下的 5 个宏来屏蔽对应用程序可能出现的填充字节。
#include#include /* for ALIGN macro on many implementations */ struct cmsghdr* CMSG_FIRSTHDR(struct msghdr *mhdrptr); /* 返回值:指向第一个 cmsghdr 结构的指针,若无辅助数据则为 NULL */ struct cmsghdr* CMSG_NXTHDR(struct msghdr *mhdrptr, struct cmsghdr *cmsgptr); /* 返回值:指向下一个 cmsghdr 结构的指针,若不再有辅助数据对象则为 NULL */ unsigned char* CMSG_DATA(struct cmsghdr *cmsgptr); /* 返回值:指向与 cmsghdr 结构相关联的数据的第一个字节的指针 */ unsigned int CMSG_LEN(unsigned int length); /* 返回值:给定数据量下存放到 cmsg_len 中的值 */ unsigned int CMSG_SPACE(unsigned int length); /* 返回值:给定数据量下一个辅助数据对象总的大小 */
这里需要注意的是,CMSG_FIRSTHDR 会在 msghdr 结构中没有辅助数据,或者 msg_control 为一个空指针,或者 cmsg_len 小于一个 cmsghdr 结构的大小时返回一个空指针。此外,CMSG_FIRSTHDR 宏的许多现有实现并不检查 msg_controllen 而直接返回 cmsg_control 的值,为保险起见,最好在调用该宏之前测试 msg_controllen 的值。
CMSG_LEN 和 CMSG_SPACE 的区别在于,前者不计算辅助数据对象中数据部分后可能的填充字节,因而返回的是用于存放在 cmsg_len 成员中的值,后者则会加上结尾处可能的填充字节,因此返回的是为辅助数据对象动态分配空间的大小值。
这几个宏可以如下形式的伪代码使用。
struct msghdr msg; struct cmsghdr *cmsgptr; /* fill in msg structure */ /* call recvmsg() */ for(cmsgptr=CMSG_FIRSTHDR(&msg); cmsgptr!=NULL; cmsgptr=CMSG_NXTHDR(&msg, cmsgptr)){ if(cmsgptr->cmsg_level == ... && cmsgptr->cmsg_type == ...){ u_char *ptr = CMSG_DATA(cmsgptr); /* process data pointed to by ptr */ } }