套接字之msghdr結構


用戶端在使用sendmsg/recvmsg發送或者接收數據時,會使用msghdr來構造消息,其對應的內核結構為user_msghdr;其中msg_iov向量指向了多個數據區,msg_iovlen標識了數據區個數;在通過系統調用進入內核后,該結構中的信息會拷貝給內核的msghdr結構;

 1 /* 用戶空間的消息頭 */
 2 struct user_msghdr {
 3     /* 指向地址結構 */
 4     void        __user *msg_name;    /* ptr to socket address structure */
 5     /* 地址結構長度 */
 6     int        msg_namelen;        /* size of socket address structure */
 7     /* 數據 */
 8     struct iovec    __user *msg_iov;    /* scatter/gather array */
 9     /* 數據區個數 */
10     __kernel_size_t    msg_iovlen;        /* # elements in msg_iov */
11     /* 控制信息 */
12     void        __user *msg_control;    /* ancillary data */
13     /* 控制信息緩沖區長度 */
14     __kernel_size_t    msg_controllen;        /* ancillary data buffer length */
15 
16     /* 接收信息的標志 */
17     unsigned int    msg_flags;        /* flags on received message */
18 };

 

在套接字發送接收系統調用流程中,send/recv,sendto/recvfrom,sendmsg/recvmsg最終都會使用內核中的msghdr來組織數據,如下,其中msg_iter為指向數據區域的向量匯總信息,其中數據區指針可能包含一個或者多個數據區,對於send/sendto其只包含了一個數據區;

 1 /*
 2  *    As we do 4.4BSD message passing we use a 4.4BSD message passing
 3  *    system, not 4.3. Thus msg_accrights(len) are now missing. They
 4  *    belong in an obscure libc emulation or the bin.
 5  */
 6  
 7 struct msghdr {
 8     /* 指向socket地址結構 */
 9     void        *msg_name;    /* ptr to socket address structure */
10     /* 地址結構長度 */
11     int        msg_namelen;    /* size of socket address structure */
12     /* 數據 */
13     struct iov_iter    msg_iter;    /* data */
14     /* 控制信息 */
15     void        *msg_control;    /* ancillary data */
16     /* 控制信息緩沖區長度 */
17     __kernel_size_t    msg_controllen;    /* ancillary data buffer length */
18 
19     /* 接收信息的標志 */
20     unsigned int    msg_flags;    /* flags on received message */
21 
22     /* 異步請求控制塊 */
23     struct kiocb    *msg_iocb;    /* ptr to iocb for async requests */
24 };

 

向量指向的數據通過iov_iter進行匯總信息和調整指向,其中iov為多個數據區的首地址,nr_segs為數據區個數;

 1 struct iov_iter {
 2     int type; /* 類型,讀寫方向,以及數據指針類型ITER_XXX */
 3     size_t iov_offset; /* 偏移 */
 4     size_t count; /* 數據總字節數 */
 5     union {
 6         /* 數據向量指針 */
 7         const struct iovec *iov;
 8         const struct kvec *kvec;
 9         const struct bio_vec *bvec;
10         struct pipe_inode_info *pipe;
11     };
12     union {
13         /* 向量中的數據塊數量 */
14         unsigned long nr_segs;
15         struct {
16             int idx;
17             int start_idx;
18         };
19     };
20 };

 

對於每個數據區,iovec記錄了數據區的首地址以及數據長度;

1 /* 一個數據區的信息 */
2 struct iovec
3 {
4     /* 數據區地址 */
5     void __user *iov_base;    /* BSD uses caddr_t (1003.1g requires void *) */
6     /* 數據區長度 */
7     __kernel_size_t iov_len; /* Must be size_t (1003.1g) */
8 };

 

總的數據組織結構如下:

 1 struct msghdr{
 2     iov_iter {
 3         type
 4         iov_offset
 5         count   | total_buff_len = buff0_len + buff1_len + buff2_len ?
 6         ---------
 7         iov_base|------>[buff0]
 8         iov_len | buff0_len
 9         ---------
10         iov_base|------>[buff1]
11         iov_len | buff1_len
12         ---------
13         iov_base|------>[buff2]
14         iov_len | buff2_len
15         ---------
16         nr_segs | iov_count = 3
17        
18     }
19  }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM