简介struct cmsghdr结构
生活随笔
收集整理的這篇文章主要介紹了
简介struct cmsghdr结构
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
附屬信息可以包括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结构的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2020年上半年巨量引擎手机行业白皮书
- 下一篇: 迈向万亿市场的直播电商