套接字之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  }

原文地址:https://www.cnblogs.com/wanpengcoder/p/11749287.html

时间: 2024-11-04 19:01:54

套接字之msghdr结构的相关文章

分析linux中套接字的实现-------创建

套接字是一种使用系统的文件描述符和系统进程进行通信的一种方法. 1.下面是描述套接字地址的结构体: struct sockaddr { sa_family_t sa_family; /* address family, AF_xxx */ 如果使用了tcp/ip协议,AF_INET char sa_data[14]; /* 14 bytes of protocol address */ }; 2.socket的系统调用: 我们创建套接字都是用socket来创建. socket的系统调用: //每

apue学习笔记(第十六章 网络IPC:套接字)

本章将考察不同计算机(通过网络连接)上的进程相互通信的机制:网络进程间通信. 套接字描述符 正如使用文件描述符访问文件,应用程序用套接字描述符访问套接字. 许多处理文件描述符函数(如read和write)可以用于处理套接字描述符.调用socket函数创建一个套接字 #include <sys/socket.h> int socket(int domain,int type,int protocol); 参数domain(域)确定通信的特性,包括地址格式.下图总结了POSIX.1指定的各个域,每

Linux/UNIX套接字连接

套接字连接 套接字是一种通信机子.凭借这样的机制.客户/server系统的开发工作既能够在本地单机上进行.也能够夸网络进行. 套接字的创建和使用与管道是有差别的.由于套接字明白地将客户和server区分开来. 套接字连接: 首先,server应用程序用系统调用socket来创建一个套接字,它是系统分配给该server进程的类似文件描写叙述符的资源,它不能与其它进程共享. 接下来.server进程会给套接字起个名字.本地套接字的名字是Linux文件系统中的文件名称,对于网络套接字它的名字是与客户连

sockets: 套接字选项相关的系统调用

########################################################### 套接字选项相关的系统调用: ########################################################### 将optval指向的单元中的值设置给optname选项: int setsockopt(int sockfd, int level, int optname, const void *optval,socklen_t optlen)

linux 套接字编程入门--Hello World

下述代码是linux套接字编程的入门代码.分为服务端和客户端源码. 服务端代码的主要流程是绑定ip地址和端口号建立套接字,等待客户端发起访问.接受客户端请求之后,向客户端发送字符串"hello world",关闭套接字,结束程序. 客户端代码的主要流程是向服务端对应的套接字发起请求,读取服务端发送的数据,并且打印出来. 代码已经详细注释,更多细节不再赘述. server.cpp #include<stdio.h> #include<stdlib.h> #incl

(一)网络编程基础之套接字入门

套接字基础 首先,我们来思考下这样一个问题:为什么要使用套接字进行网络编程? 答:Linux环境下使用套接字进行进程之间的通信.套接字接口(socket interface)是一组函数,也是操作系统提供给应用程序的接口.在Unix系统中,套接字和Unix I/O函数结合起来,用来创建网络应用程序.(也就是说,操作系统对外只提供了套接字作为网络通信的接口,假如想进行网络通信,套接字我们用也得用,不用也得用,而且使用套接字来进行网络通信是十分通用的方法).这里最典型的就是客户端--服务器模型. 因特

套接字I/O模型-完成端口IOCP

“完成端口”模型是迄今为止最为复杂的一种I/O模型.然而,假若一个应用程序同时需要管理为数众多的套接字,那么采用这种模型,往往可以达到最佳的系统性能!但不幸的是,该模型只适用于Windows NT和Windows 2000操作系统.因其设计的复杂性,只有在你的应用程序需要同时管理数百乃至上千个套接字的时候,而且希望随着系统内安装的CPU数量的增多,应用程序的性能也可以线性提升,才应考虑采用“完成端口”模型.要记住的一个基本准则是,假如要为Windows NT或Windows 2000开发高性能的

Unix 网络编程(四)- 典型TCP客服服务器程序开发实例及基本套接字API介绍

写在开头: 在上一节中我们学习了一些基础的用来支持网络编程的API,包括"套接字的地址结构"."字节排序函数"等.这些API几乎是所有的网络编程中都会使用的一些,对于我们正确的编写网络程序有很大的作用.在本节中我们会介绍编写一个基于TCP的套接字程序需要的一些API,同时会介绍一个完整的TCP客户服务器程序,虽然这个程序功能相对简单,但确包含了一个客户服务器程序所有的步骤,一些复杂的程序也都是在此基础上进行扩充.在后面随着学习的深入,我们会给这个程序添加功能. 下面

《网络编程》基本 TCP 套接字编程

在进行套接字编程之前必须熟悉其地址结构,有关套接字的地址结构可参考文章<套接字编程简介>.基于 TCP 的套接字编程的所有客户端和服务器端都是从调用socket 开始,它返回一个套接字描述符.客户端随后调用connect 函数,服务器端则调用 bind.listen 和accept 函数.套接字通常使用标准的close 函数关闭,但是也可以使用 shutdown 函数关闭套接字.下面针对套接字编程实现过程中所调用的函数进程分析.以下是基于 TCP 套接字编程的流程图: socket 函数 套接