资讯专栏INFORMATION COLUMN

Linux用户态与内核态通信的几种方式

crossoverJie / 2061人阅读

摘要:我们平常在写代码时,一般是在用户空间,通过系统调用函数来访问内核空间,这是最常用的一种用户态和内核态通信的方式。它本质上还是用到了文件的读写操作,来完成用户态和内核态的通信。总结用户态和内核态通信主要的四种方式,其中和是最常见的方式。

本文首发于我的公众号 Linux云计算网络(id: cloud_dev),专注于干货分享,号内有 10T 书籍和视频资源,后台回复「1024」即可领取,欢迎大家关注,二维码文末可以扫。

Linux 用户态和内核态由于 CPU 权限的限制,通信并不像想象中的使用进程间通信方式那么简单,今天这篇文章就来看看 Linux 用户态和内核态究竟有哪些通信方式。

我们平常在写代码时,一般是在用户空间,通过系统调用函数来访问内核空间,这是最常用的一种用户态和内核态通信的方式。(关于 Linux 用户态和内核态可以参考 xx)

除此之外,还有以下四种方式:

procfs(/proc)

sysctl(/proc/sys)

sysfs(/sys)

netlink 套接口

procfs(/proc)

procfs进程文件系统 的缩写,它本质上是一个伪文件系统,为什么说是 文件系统呢?因为它不占用外部存储空间,只是占用少量的内存,通常是挂载在 /proc 目录下。

我们在该目录下看到的一个文件,实际上是一个内核变量。内核就是通过这个目录,以文件的形式展现自己的内部信息,相当于 /proc 目录为用户态和内核态之间的交互搭建了一个桥梁,用户态读写 /proc 下的文件,就是读写内核相关的配置参数。

比如常见的 /proc/cpuinfo/proc/meminfo/proc/net 就分别提供了 CPU、内存、网络的相关参数。除此之外,还有很多的参数,如下所示:

root@ubuntu:~# ls /proc/
1     1143  1345  1447  2     2292  29   331   393  44    63    70    76   acpi       diskstats    irq          locks         sched_debug    sysvipc            zoneinfo
10    1145  1357  148   20    23    290  332   396  442   64    7019  77   asound     dma          kallsyms     mdstat        schedstat      thread-self
1042  1149  1361  149   2084  2425  291  34    398  45    65    7029  8    buddyinfo  driver       kcore        meminfo       scsi           timer_list
1044  1150  1363  15    2087  25    3    3455  413  46    66    7079  83   bus        execdomains  keys         misc          self           timer_stats
1046  1151  1371  16    2090  256   30   35    418  47    6600  7080  884  cgroups    fb           key-users    modules       slabinfo       tty
1048  1153  1372  17    21    26    302  36    419  5     67    71    9    cmdline    filesystems  kmsg         mounts        softirqs       uptime
11    1190  1390  18    22    27    31   37    420  518   6749  72    96   consoles   fs           kpagecgroup  mtrr          stat           version
1126  12    143   182   2214  28    32   373   421  524   68    73    97   cpuinfo    interrupts   kpagecount   net           swaps          version_signature
1137  1252  1434  184   2215  280   327  38    422  525   69    74    98   crypto     iomem        kpageflags   pagetypeinfo  sys            vmallocinfo
1141  13    144   190   2262  281   33   39    425  5940  7     75    985  devices    ioports      loadavg      partitions    sysrq-trigger  vmstat

可以看到,这里面有很多的数字表示的文件,这些其实是当前系统运行的进程文件,数字表示进程号(PID),每个文件包含该进程所有的配置信息,包括进程状态、文件描述符、内存映射等等,我们可以看下:

root@ubuntu:~# ls /proc/1/
attr/            cmdline          environ          io               mem              ns/              pagemap          schedstat        stat             timers
autogroup        comm             exe              limits           mountinfo        numa_maps        personality      sessionid        statm            uid_map
auxv             coredump_filter  fd/              loginuid         mounts           oom_adj          projid_map       setgroups        status           wchan
cgroup           cpuset           fdinfo/          map_files/       mountstats       oom_score        root/            smaps            syscall          
clear_refs       cwd/             gid_map          maps             net/             oom_score_adj    sched            stack            task/

综上,内核通过一个个的文件来暴露自己的系统配置信息,这些文件,有些是只读的,有些是可写的,有些是动态变化的,比如进程文件,当应用程序读取某个 /proc/ 文件时,内核才会去注册这个文件,然后再调用一组内核函数来处理,将相应的内核参数拷贝到用户态空间,这样用户读这个文件就可以获取到内核的信息。一个大概的图示如下所示:

sysctl

我们熟悉的 sysctl 是一个 Linux 命令,man sysctl 可以看到它的功能和用法。它主要是被用来修改内核的运行时参数,换句话说,它可以在内核运行过程中,动态修改内核参数。

它本质上还是用到了文件的读写操作,来完成用户态和内核态的通信。它使用的是 /proc 的一个子目录 /proc/sys。和 procfs 的区别在于:

procfs 主要是输出只读数据,而 sysctl 输出的大部分信息是可写的。

例如,我们比较常见的是通过 cat /proc/sys/net/ipv4/ip_forward 来获取内核网络层是否允许转发 IP 数据包,通过 echo 1 > /proc/sys/net/ipv4/ip_forward 或者 sysctl -w net.ipv4.ip_forward=1 来设置内核网络层允许转发 IP 数据包。

同样的操作,Linux 也提供了文件 /etc/sysctl.conf 来让你进行批量修改。

sysfs

sysfs 是 Linux 2.6 才引入的一种虚拟文件系统,它的做法也是通过文件 /sys 来完成用户态和内核的通信。和 procfs 不同的是,sysfs 是将一些原本在 procfs 中的,关于设备和驱动的部分,独立出来,以 “设备树” 的形式呈现给用户。

sysfs 不仅可以从内核空间读取设备和驱动程序的信息,也可以对设备和驱动进行配置。

我们看下 /sys 下有什么:

# ls /sys
block  bus  class  dev  devices  firmware  fs  hypervisor  kernel  module  power

可以看到这些文件基本上都跟计算机的设备和驱动等息息相关的。更多关于这些文件的解释大家可以自行了解,这里就不过多展开了。

netlink

netlink 是 Linux 用户态与内核态通信最常用的一种方式。Linux kernel 2.6.14 版本才开始支持。它本质上是一种 socket,常规 socket 使用的标准 API,在它身上同样适用。比如创建一个 netlink socket,可以调用如下的 socket 函数:

#include 
#include 
#include 

netlink_socket = socket(AF_NETLINK, socket_type, netlink_family);

netlink 这种灵活的方式,使得它可以用于内核与多种用户进程之间的消息传递系统,比如路由子系统,防火墙(Netfilter),ipsec 安全策略等等。

引申:

net-tools 工具通过 procfs(/proc) 和 ioctl 系统调用去访问和改变内核网络参数配置,而 iproute2 则通过 netlink 套接字接口与内核通信,前者已经被淘汰了,后者逐步成为标准。

总结

Linux 用户态和内核态通信主要的四种方式,其中 netlink 和 procfs 是最常见的方式。


后台回复“加群”,带你进入高手如云交流群

我的公众号 「Linux云计算网络」(id: cloud_dev) ,号内有 10T 书籍和视频资源,后台回复 「1024」 即可领取,分享的内容包括但不限于 Linux、网络、云计算虚拟化、容器Docker、OpenStack、Kubernetes、工具、SDN、OVS、DPDK、Go、Python、C/C++编程技术等内容,欢迎大家关注。

参考:

https://www.ibm.com/developer...

https://fasionchan.com/blog/2...

https://zh.wikipedia.org/wiki...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/11684.html

相关文章

  • Linux用户内核通信几种方式

    摘要:我们平常在写代码时,一般是在用户空间,通过系统调用函数来访问内核空间,这是最常用的一种用户态和内核态通信的方式。它本质上还是用到了文件的读写操作,来完成用户态和内核态的通信。总结用户态和内核态通信主要的四种方式,其中和是最常见的方式。 本文首发于我的公众号 Linux云计算网络(id: cloud_dev),专注于干货分享,号内有 10T 书籍和视频资源,后台回复「1024」即可领取,...

    sarva 评论0 收藏0
  • 内核用户

    摘要:内核态与用户态概念的设计哲学之一就是对不同的操作赋予不同的执行等级,就是所谓特权的概念,即与系统相关的一些特别关键的操作必须由最高特权的程序来完成。 内核态与用户态 showImg(https://segmentfault.com/img/remote/1460000011899643); 1 概念 Linux的设计哲学之一就是:对不同的操作赋予不同的执行等级,就是所谓特权的概念,即与...

    张利勇 评论0 收藏0
  • 浅谈Service Mesh体系中的Envoy

    摘要:在中指的是一些可插拔和可组合的逻辑处理层。通过健康检查服务来对集群成员服务状态进行检查。新老进程采用基本的协议使用通讯。新进程启动并完成所有初始化工作后,向老进程请求监听套接字的副本。新进程接管套接字后,通知老进程关闭套接字。 摘要: 提到Envoy就不得不提Service Mesh,说到Service Mesh就一定要谈及微服务了,那么我们就先放下Envoy,简单了解下微服务、Se...

    FuisonDesign 评论0 收藏0
  • 你弄懂Kafka使用什么性能策略吗

    摘要:明确的性能阵地首先,明确研究问题的方向。以时间换空间实时性与吞吐量为了解决网络请求过多的问题,生产者会合并多条消息再提交,降低网络的频繁,以牺牲一点延迟换取更高的吞吐量。 本文是我研究Kafka的一点心得,欢迎指出纰漏更多访问我的博客 前言 Kafka 作为愈加流行的流处理平台,让人好奇它为何如此受人青睐,盛名之下无虚士,我从性能角度来探索 Kafka 的奥妙。 明确Kafka的性能...

    刘明 评论0 收藏0
  • Linux系统调用原理

    摘要:操作系统通过系统调用为运行于其上的进程提供服务。是更高层次的库函数,建立在系统调用之上,实现数据格式化等功能。而库函数与系统调用处理函数之间,由于涉及用户态与内核态的切换,要复杂一些。 操作系统通过系统调用为运行于其上的进程提供服务。 当用户态进程发起一个系统调用, CPU 将切换到 内核态 并开始执行一个 内核函数 。 内核函数负责响应应用程序的要求,例如操作文件、进行网络通讯或者申...

    Jonathan Shieber 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<