(三)获取linux内核的系统信息

2023-11-06

这一章,使用qt来获取linux内核的系统信息并显示到界面上。这里的系统信息包括CPU的使用率,CPU的温度,内存信息以及硬盘信息。

 

  • CPU温度

  • NanoPI Fire3的开发团队为系统提供了读取CPU温度的接口,一个设备文件,使用命令查看CPU温度

  • cat /sys/class/thermal/thermal_zone0/temp

  • 文件里面的值为65000,这里的值除1000就是实际的温度值,65000/1000=65。说明现在的CPU温度为65度。

    知道了设备文件,那么就可以开始写程序了。

  • //获取CPU温度
    QString temp_file_name("/sys/class/thermal/thermal_zone0/temp");
    file_info.setFile(temp_file_name);
    if(file_info.isFile())
    {
        QFile temp_file(temp_file_name);
        if(temp_file.open(QFile::ReadOnly))
        {
            QString cpu_temp_str = temp_file.readAll();
            cpu_info_data.temp = static_cast<double>((double)(cpu_temp_str.toDouble()) / 1000.0);
    
            qDebug() << QString("cpu temp : %1°C").arg(QString::number(cpu_info_data.temp,'f',2));
            temp_file.close();
        }
    }
    else
    {
        qDebug() << "No file named : " << temp_file_name;
        cpu_info_data.temp = 0;
    }
    

    先判断文件是否存在,如果不存在那么直接返回。如果存在则使用QFile进行信息读取。然后把信息转换为double型进行存储。

    为了方便的数据处理,我建立了一个结构体

  • // system info struct
    struct CpuInfo_data
    {
        long long total;
        long long usr;
        long long nic;
        long long sys;
        long long idle;
        long long iowait;
        long long irq;
        long long softirq;
        long long steal;
        double rate;
        double temp;
    };
    

    其中temp是温度的值,其他的为CPU使用率所使用

  • CPU使用率

CPU使用率如何获得,我们都知道linux中有一个top命令可以查看CPU的信息

输入top命令,出来的最上面5行便是系统信息,我们关心的是3,4行,CPU使用率和内存信息。

CPU这一行的id属性的意思是剩余的CPU资源,总共是100,所以可以算出已经使用的CPU资源为100-92.5

大家都知道linux中的所有命令都来自于busybox的支持,如果不知道,可以暂停一下,去了解一下busybox是什么。

所以我们可以通过busybox中top命令的实现源码来判断这里的信息时如何读取出来的。

去busybox官网下载源码(如果打不开网站,可以在我的github下载)

https://busybox.net/downloads/

解压后通过source insight软件打开源码(source insight不会用的先去查找一下相关资料)

打开source insight,在右边输入top,打开top.c文件

先打开main函数,这里发现程序将工作目录切换到了/proc目录。

一路跟踪到do_stats函数,进入该函数

再进入get_jiffy_counts函数

这个函数解释了top命令中的cpu信息如何来的

首先看到,打开了stat文件,根据main函数中切换目录,可以判断这个文件名为/proc/stat,到linux系统中查看

ls /proc/stat

有这个文件,那么看看里面有什么

https://blog.csdn.net/ibless/article/details/85177175

关于/proc/stat的解析,可以参考一下这篇文章

有9行CPU开头的数据,其中CPU为总的CPU数据,其他0-7为各个核心的数据(没错,我这块板是8核的)。

现在我需要的是总CPU使用率,所以只关心第一行就行了。

看看busybox如何处理的

首先用fscanf格式化读取文件中的数据,并分别放到结构体保存,这里我们不用关心jif这个结构体是什么,只需要通过%lld知道这里的数据类型是long long就可以了。

接着求了一个总和,可以看到就是把其他的全部加起来。

总和减去剩余的,就是已经使用的。

公式如下

Total CPU time since boot = user+nice+system+idle+iowait+irq+softirq+steal
Total CPU Idle time since boot = idle + iowait
Total CPU usage time since boot = Total CPU time since boot - Total CPU Idle time since boot
Total CPU percentage = Total CPU usage time since boot/Total CPU time since boot * 100%

也就是说,CPU的占用率= (1 - (现在时刻CPU Idle – 前一时刻CPU Idle) /  (现在时刻CPU Total – 前一时刻CPU Total))

过程知道了,那么可以使用QT编写程序了。结构体上面已经展示过了,这里就直接给代码

先在类中声明一个全局的变量,用于保存前一时刻的CPU信息

CpuInfo_Data pre_cpu_info_data;

数据处理过程如下

    // 初始化为0
    struct CpuInfo_Data cpu_info_data;
    cpu_info_data.usr = 0;
    cpu_info_data.nic = 0;
    cpu_info_data.sys = 0;
    cpu_info_data.idle = 0;
    cpu_info_data.iowait = 0;
    cpu_info_data.irq = 0;
    cpu_info_data.softirq = 0;
    cpu_info_data.steal = 0;
    cpu_info_data.temp = 0;
    cpu_info_data.total = 0;
    cpu_info_data.rate = 0;
    cpu_info_data.freq = 0;

    //获得CPU占用信息
    QString info_file_name("/proc/stat");
    QFileInfo file_info(info_file_name);
    //判断文件是否存在
    if(file_info.isFile())
    {
        //提取文件中的数据
        std::FILE *cpu_fd = std::fopen(info_file_name.toLatin1().data(),"r");
        if(std::fscanf(cpu_fd,"cpu  %lld %lld %lld %lld %lld %lld %lld %lld",\
                    &cpu_info_data.usr,&cpu_info_data.nic,&cpu_info_data.sys, \
                    &cpu_info_data.idle,&cpu_info_data.iowait, \
                    &cpu_info_data.irq,&cpu_info_data.softirq, \
                    &cpu_info_data.steal) < 4)
        {
            qDebug() << "failed to read " << info_file_name;
        }
        std::fclose(cpu_fd);

        //计算CPU总资源数
        cpu_info_data.total = cpu_info_data.usr + cpu_info_data.nic + cpu_info_data.sys + cpu_info_data.idle + cpu_info_data.iowait + cpu_info_data.irq + cpu_info_data.softirq + cpu_info_data.steal;

        long long total = cpu_info_data.total;
        long long idle = cpu_info_data.idle + cpu_info_data.iowait;
        long long pre_total = pre_cpu_info_data.total;
        long long pre_idle = pre_cpu_info_data.idle + pre_cpu_info_data.iowait;

        cpu_info_data.rate = static_cast<double>((double)((total-pre_total) - (idle-pre_idle)) / (double)(total-pre_total)) * 100;
        pre_cpu_info_data = cpu_info_data;

        //qDebug() << QString("cpu rate : %1%").arg(cpu_info_data.rate);
    }
    else
    {
        qDebug() << "No file named : " << info_file_name;
    }

因为是C++语言,所以使用std::fscanf代替fscanf,其实参数都是一样的。求使用率的时候,因为是double所以记得使用static_case<double>进行类型转换。最后使用QString::number(cpu_info_data.rate, 'f', 2)方法输出小数点后2位的数据。

  • 内存信息

上面说到的top命令同样也能读取内存数据,那么我们在top.c中找一下是如何实现的。

找到display_generic函数

发现这里使用的文件是meminfo,也就是/proc/meminfo,同样,我们在linux下查看这个文件里面的数据。

cat /proc/meminfo

可以看到是内存的所有信息,但是我们只关注前两行就可以了。

MemTotal是总的内存大小

MemFree是空闲的内存大小

那么可以得出使用的内存大小为MemTotal-MemFree,使用率为(MemTotal-MemFree)/MemTotal * 100

同样使用格式化读取,%lu为long unsigned int类型

那么接下来可以编写QT程序

定义结构体

struct MemInfo_data
{
    long unsigned int total;
    long unsigned int free;
    long unsigned int used;
    double rate;
};

读取文件信息

    QString file_info_name("/proc/meminfo");
    QFileInfo file_info(file_info_name);
    if(file_info.isFile())
    {
        std::FILE *mem_fd = std::fopen(file_info_name.toLatin1().data(),"r");
        std::fscanf(mem_fd,"MemTotal: %lu kB\n",&mem_info_data.total);
        std::fscanf(mem_fd,"MemFree: %lu kB\n",&mem_info_data.free);
        std::fclose(mem_fd);
        mem_info_data.used = mem_info_data.total - mem_info_data.free;
        mem_info_data.rate = static_cast<double>((double)mem_info_data.used / (double)mem_info_data.total) * 100.0;

        mem_info_data.total = mem_info_data.total / 1024;
        mem_info_data.used  = mem_info_data.used  / 1024;
        mem_info_data.free  = mem_info_data.free  / 1024;

        //qDebug() << QString("Mem : %1 / %2 MB    %3%").arg(mem_info_data.used).arg(mem_info_data.total).arg(QString::number(mem_info_data.rate,'f',2));
    }
    else
    {
        qDebug() << "No file named : " << file_info_name;
        return;
}

同样记得注意int-double的类型转换,读取数据的单位是KB,我想用MB所以除1024

  • 硬盘信息

在linux上我们一般使用df命令来查看硬盘信息,这个命令也是由busybox实现,在源码中找到df.c,进入main函数。这里要注意一个结构体struct statfs,这个结构体保存了所有的硬盘信息,是内核实现的,不需要我们另外读取文件得到,不了解的先去查一下这个结构体的使用。

往下看,来到红框这里,这个函数的作用是读取以mount_point为结点的目录在硬盘中的空间使用情况,并放入s结构体,前面我们知道了s就是struct statfs

那么总的空间大小为f_blocks*f_bsize,空闲的空间大小为f_bfree*f_bsize

那么已经使用的空间大小为总的空间大小减去空闲的空间大小

编写QT代码

要使用struct statfs结构体,要先包括两个头文件

#include <sys/statfs.h>
#include <sys/vfs.h>

先定义结构体

struct DiskInfo_data
{
    long long total;
    long long free;
    long long used;
    double rate;
};

读取信息过程

    struct statfs disk_info;
    QString path = "/";

    if (statfs(path.toLatin1().data(), &disk_info) == -1)
    {
        qDebug() << "Failed to get file disk infomation";
        return;
    }

    disk_info_data.total = disk_info.f_blocks * disk_info.f_bsize;
    disk_info_data.free = disk_info.f_bfree * disk_info.f_bsize;
    disk_info_data.used = disk_info_data.total - disk_info_data.free;
    disk_info_data.rate = static_cast<double>((double)disk_info_data.used / (double)disk_info_data.total) * 100.0;

    disk_info_data.total = disk_info_data.total / 1024 / 1024;
    disk_info_data.free  = disk_info_data.free  / 1024 / 1024;
    disk_info_data.used  = disk_info_data.used  / 1024 / 1024;

    //double total = static_cast<double>((double)disk_info_data.total / 1024);
    //double used = static_cast<double>((double)disk_info_data.used / 1024);

    //qDebug() << QString("Disk : %1 / %2 GB    %3%").arg(QString::number(used,'f',2)).arg(QString::number(total,'f',2)).arg(QString::number(disk_info_data.rate,'f',2));

这里我想得到根文件系统的使用信息,所以传入的第一个参数为”/”,同样注意类型转换,以及单位转换,初始数据是字节为单位,我想使用GB为单位,所以要除三次1024

  • 补充说明

4个系统数据都读取完成,于是我将他们整合起来,开一个线程来跑,每秒读取一次信息并返回给界面,使用QLabel显示。

这里遇到了一个问题就是,我使用了QT信号和槽机制来传输我自定义的三个结构体,但是信号和槽并不支持使用自定义的结构作为参数,所以报错

QObject::connect: Cannot queue arguments of type ‘CpuInfo_data’ (Make sure ‘CpuInfo_data’ is registed using qRegisterMetaType().)

解决方法

包含一个头文件

#include <QMetaType>

然后在connect信号槽之前注册自定义的结构体

    //使用自定义结构体在信号槽中传递时需要先注册,否则会报错
    qRegisterMetaType<CpuInfo_data>("CpuInfo_data");
    qRegisterMetaType<MemInfo_data>("MemInfo_data");
    qRegisterMetaType<DiskInfo_data>("DiskInfo_data");

这样就可以解决问题

运行结果在上一章已经展示过了。

 

Qt完整源码放在github上,有需要可以自行下载。 代码名称为190516.zip

https://github.com/ljy980330/opencv_face_sys

 

有任何问题可以在下面给我留言!大家一起学习!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

(三)获取linux内核的系统信息 的相关文章

随机推荐

  • Docker CE 镜像源站 CentOS 7 (使用yum进行安装)

    step 1 安装必要的一些系统工具 sudo yum install y yum utils device mapper persistent data lvm2 Step 2 添加软件源信息 sudo yum config manage
  • KMP算法之基础思想篇

    KMP算法是快速求字符串P 是不是字符串S的子串的一个算法 具体案例呢 可以看力扣的28题 实现 strStr 题意也很简单 就是找出P在S中出现的第一个位置 实际上就是找子串 这种最简单的方法就是暴力 直接两层for循环 O n m 的复
  • 前端实现元素拖拽的组件react-draggable

    参考官网https www npmjs com package react draggable
  • jquery绑定点击事件,随着点击次数的增加,发送的网络请求也累加,该如何避免此种情况?

    今天在用jQuery写项目的时候发现 当我点击部门与地方并来回切换的时候 发送的网络请求也是逐步累加 这样的情况很影响性能 很难通过压力测试 之所以会出现这样的原因是绑定的点击事件不是每点击一次就替换上一次的数据 他是逐步累积的 解决这个方
  • 蜻蜓刷脸支付就算是双胞胎也能轻松辨别

    随着科技的发展 我们进入了一个全新的时代 各类新鲜的行业也涌现 为了跟上人们生活所需 各个行业都要各自完善 更新更适合人们的产品 才能在这个信息的时代存活 我们告别了现金的时代 迎来了移动支付 这使得我们的生活更加的便捷 同样的节省了我们的
  • adb的安装和配置

    下载工具 解压后 进行环境配置 SDK 平台工具版本说明 Android 开发者 Android Developers 将adb exe所在路径 新建到Path中 adb version 可查看adb版本信息即可
  • NumPy 函数手册

    NumPy手册 文章目录 NumPy手册 获取属性 秩 形状 大小 元素数据类型 元素占用空间大小 内存地址 创建数组 创建空数组 创建零数组 创建1数组 创建对角矩阵 创建序列数组 创建概率分布的数组 已有列表 元组创建 切片 索引 切片
  • upload_libs通关教程

    Pass 01 js检查 只能上传jpg png gif js验证 上传php文件被拦截 删除js验证 上传成功 Pass 02 MIME Type验证 文件有MIME Type验证 可以用burpsuit抓包 修改Content Type
  • 【PostgreSQL 数据库技术峰会(成都站)】云原生虚拟数仓 PieCloudDB Database 的架构和关键模块实现...

    2023年6月17日 中国开源软件推进联盟 PostgreSQL 分会在成都举办了数据库技术峰会 此次峰会以 新机遇 新态势 新发展 为主题 结合当下信创热潮 人工智能等产业变革背景 探讨 PostgreSQL 数据库在这些新机遇下的发展前
  • 浏览器播放rtsp视频流:1、开源方案

    浏览器播放rtsp视频流 1 开源方案 文章目录 浏览器播放rtsp视频流 1 开源方案 1 方案一 html5 websocket rtsp proxy 实现视频流直播 1 1 实现原理 1 2 实现步骤 1 3 优缺点 1 4 参考链接
  • LeetCode # 452 投飞镖刺破气球

    在二维空间中有许多球形的气球 对于每个气球 提供的输入是水平方向上 气球直径的开始和结束坐标 由于它是水平的 所以y坐标并不重要 因此只要知道开始和结束的x坐标就足够了 开始坐标总是小于结束坐标 平面内最多存在104个气球 一支弓箭可以沿着
  • 鸿蒙pc系统镜像,鸿蒙系统有pc版么_鸿蒙系统有pc版安装方法

    鸿蒙系统作为华为推出的一款操作系统 它跟其他安卓ios系统还是有很大区别的接 但是华为除了有手机还有电视使用鸿蒙系统之外电脑也是华为手机不可缺少的一款 那鸿蒙系统pc版怎么下载呢 1 鸿蒙系统pc版安装方法 首先在电脑上插入U盘 然后打开制
  • 钉钉内网测试-超简单

    环境 win10 python3 钉钉内网穿透官网 两步实现内网穿透 一 下载穿透工具 穿透工具 11 8M 然后启动 进入命令行 cd windows 64 ding config ding cfg subdomain abcde 808
  • expdp数据泵导出oracle某表带时间查询的写法

    expdp scott tiger orcl directory dump dir dumpfile expdp dmp tables emp query where tjsj to date 2020 03 yyyy mm
  • yolop源码train.py学习

    因为要做一个可行驶区域和车道线的任务 所以选了yolop 看他的刷榜还可以 yolop的算法解读后边找了链接再贴出来 花花花大神的博客 我们先从 tools train py 开始debug train py 结构 import xxx d
  • linux入门之awk和shell变量传递

    一 awk使用shell中的普通变量 方法1 使用引号法 aa hello awk BEGIN print aa 输出 aa awk BEGIN print aa 输出hello awk BEGIN print aa 输出空 aa hell
  • metasploit(MSF)渗透超细解说 -- 小黑渗透工具

    metasploit Framework msf 里带数千个已知的软件漏洞 并保持持续更新 Metasploit可以用来信息收集 漏洞探测 漏洞利用等渗透测试的全流程 采用Ruby语言编写 黑掉整个宇宙的称号 初心 记录msfconsole
  • 比尔·盖茨的传奇

    比尔 盖茨的传奇 传奇人生始自少年 比尔盖茨的编程人生在他十三岁就开始了 他进入了湖畔中学 LakesideSchool 湖畔中学是当时为数不多的拥有计算机 PDP 10 的学校 但是机器使用时间严重受限 因而比尔盖茨和计算机公司达成了协议
  • 黑马程序员Spring视频教程,全面深度讲解spring5底层原理 学习笔记

    介绍 代码仓库地址 https gitee com CandyWall spring source study 跟着黑马满一航老师的spring高级49讲做的学习笔记 本笔记跟视频内容的项目名称和代码略有不同 我将49讲的代码每一讲的代码都
  • (三)获取linux内核的系统信息

    这一章 使用qt来获取linux内核的系统信息并显示到界面上 这里的系统信息包括CPU的使用率 CPU的温度 内存信息以及硬盘信息 CPU温度 NanoPI Fire3的开发团队为系统提供了读取CPU温度的接口 一个设备文件 使用命令查看C