【操作系统】基于/proc文件的Linux资源监视器


我们选择采用 Python 语言作为这次实验的开发语言。同时使用Tkinter 模块实现 GUI 图形界面。

一、设计流程

整个资源管理器分为四个模块:CPU、内存、进程和硬盘。
在这里插入图片描述

二、内存模块

在/proc 目录中的 meminfo 文件记录有内存的基本信息。通过使用 cat 命令查看 meminfo 文件的内容,从中确定了我们需要读取的字段:
1、读取/proc/meminfo 文件, 其中我们需要的字段有:(单位均为 KB)
在这里插入图片描述通过 Python 的字符串分割函数, 将以上的值存入数据结构字典中。

2、计算内存和交换空间的使用率:
内存使用率: 1 – MemFree / MemTotal
交换空间的内存使用率: 1 – SwapFree / MemTotal
3、相关代码

代码如下(示例):

def read_meminfo(read_type):
    with open('/proc/meminfo',read_type) as file:
        for line in file.readlines():
            data = line.split()
            if data[0] == 'MemTotal:':
                meminfo['mem_total'] = data[1]
            elif data[0] == 'MemAvailable:':
                meminfo['mem_available'] = data[1]
            elif data[0] == 'SwapTotal:':
                meminfo['swap_total'] = data[1]
            elif data[0] == 'SwapFree:':
                meminfo['swap_free'] = data[1]
# 已使用内存
        mem_used = float(meminfo['mem_total'])-float(meminfo['mem_available'])
# 内存使用率
        meminfo['mem_usage']=100*(mem_used/float(meminfo['mem_total']))
# 交换空间使用大小
        swap_used = float(meminfo['swap_total'])-float(meminfo['swap_free'])
# 交换空间
        meminfo['swap_usage']=100*(swap_used/float(meminfo['swap_total']))
    return meminfo
    
def get_meminfo():
    read_meminfo('r')
    meminfo['mem_usage'] = 100 * (float(meminfo['mem_total']) - float(meminfo['mem_available'])) / float(meminfo['mem_total'])
    meminfo['swap_usage'] = 100 * (float(meminfo['swap_total']) - float(meminfo['swap_free'])) / float(meminfo['swap_total'])
    return meminfo

三、CPU模块

部分代码如下:

def read_cpuinfo(read_type):
    with open('/proc/cpuinfo',read_type) as file:
        for line in file.readlines():
            data = line.split(':')
            #print(data)
# 获取cpu名  CPU属于的名字及其编号、标称主频
            if data[0].startswith('model name') :
                cpuinfos['cpu_name'] = data[1].strip('\n').strip()
# CPU的实际使用主频
            elif data[0].startswith('cpu MHz'):
#round()四舍五入
                cpuinfos['mhz'] = round(float(data[1].strip('\n').strip()) / 1024, 2)
#cpu利用率
def calc_cpuUsage():

    read_cpuinfo('r')
    read_stat('r')
    idle1 = cpuinfos['idle'].copy()
    total1 = cpuinfos['total'].copy()
#记录第一次的数据
    cpuinfos['idle'].clear()
    cpuinfos['total'].clear()

    time.sleep(0.1)

    read_stat('r')
# 重新记录一次数据
    idle2 = cpuinfos['idle']
    total2 = cpuinfos['total']
    cpuinfos['usage'].clear()
    for i in range(cpuinfos['num'] + 1):
        usage = (1-(idle2[i]-idle1[i])/(total2[i]-total1[i]))*100
        cpuinfos['usage'].append(usage)
# 获取系统启动到现在的时间(以妙为单位)
def read_uptime(read_type):
# 第一列输出的是,系统启动到现在的时间(以秒为单位),这里简记为num1;
# 第二列输出的是,系统空闲的时间(以秒为单位),这里简记为num2。
    with open('/proc/uptime', read_type) as file:
        seconds = file.read()
        t = seconds.strip('\n').split(' ')
# 返回一个包含除法和余数的元组,这里取第一个数字
        m, s = divmod(int(float(t[0])), 60)
        h, m = divmod(m, 60)
        cpuinfos['usage_time'] = ("%d:%02d:%02d" % (h, m, s))

def read_stat(read_type):
    with open('/proc/stat',read_type) as file:
        for line in file.readlines():
            data = line.split()
            if data[0].startswith('cpu'):
#cpu     user    nice    system  idle    iowait  irq softirq steal   guest   guest_nice
                total = 0
                for i in range(1, len(data)):
                    total = total+ int(data[i])

                cpuinfos['total'].append(total)
                cpuinfos['idle'].append(int(data[4]))
        cpuinfos['num'] = len(cpuinfos['total']) - 1

# def read_cpu_cache(read_type='r'):
#     """
#     获取CPU的cache,先从/sys/devices/system/cpu/中获取每个Core的Cache的级数level
#     然后获取Cache的size,
    
#     """
#     cpu_index = os.

def get_loadavg():
    with open('/proc/loadavg', 'r') as file:
        data = file.read().split()
        n = 0
        for i in loadavg.keys():
            loadavg[i] = data[n]
            n += 1
    return loadavg

def get_cpuinfos():
    calc_cpuUsage()
    read_uptime('r')
    read_meminfo('r')
    return cpuinfos

四、磁盘模块

部分代码如下:

def read_mounts():
    zoning_num = 0
    with open('/proc/mounts','r') as f:    #/proc/mounts的内容为系统当前挂载的所有文件系统
        for line in f.readlines():   #readline逐行读取
            data = line.split()    #把末尾的\n删掉
            if data[0].startswith('/dev/sda'):   #检查字符串是否是以/dev/sda开头(磁盘),如果是则返回 True
                disk_path['path'].append(data[1])        #磁盘挂载点,append()在列表末尾添加新的对象
                zoning_num += 1
        disk_number['zoning'] = zoning_num
        list_dz = [disk_path,disk_number]
    return list_dz

def read_disk():
    st = os.statvfs('/') #os模块的statvfs()方法--读取各分区挂载点,查看文件系统信息、磁盘使用情况

    #st返回值---f_blocks分区文件系统数据块总数;f_frsize基本文件系统块大小;
    #f_bfree可用块数;f_bavail非超级用户可用的空闲块
    #round四舍五入返回一个数值,1即小数位后只有1位
    total = round(st.f_blocks * st.f_frsize / 1024 /1024 /1024 , 1)         #磁盘总容量
    used = round((st.f_blocks - st.f_bfree) * st.f_frsize / 1024 / 1024 /1024 , 1)  #已使用容量
    available = round(st.f_bavail * st.f_frsize / 1024 / 1024 /1024 , 1)       #剩余可使用
    actual_total = round(used + available , 1)        #实际总容量
    usage  = round(used / (used + available) * 100, 2)       #磁盘使用率

    disk_usage['total'].append(total)
    disk_usage['actual_total'].append(actual_total)
    disk_usage['used'].append(used)
    disk_usage['available'].append(available)
    disk_usage['usage'].append(usage)

    read_mounts()    #统计磁盘使用情况
    for i in range(disk_number['zoning']):  #range返回从0开始到zoning_num的数字
        st = os.statvfs(disk_path['path'][i])
        total = round(st.f_blocks * st.f_frsize / 1024 /1024 /1024 , 1)       #分区总容量
        used = round((st.f_blocks - st.f_bfree) * st.f_frsize / 1024 / 1024 /1024 , 1)  #已使用容量
        available = round(st.f_bavail * st.f_frsize / 1024 / 1024 /1024 , 1)        #剩余可使用
        actual_total = round(used + available , 1)       #实际总容量
        usage  = round(used / (used + available) * 100, 2)   #分区使用率

        disk_usage['total'].append(total)
        disk_usage['actual_total'].append(actual_total)
        disk_usage['used'].append(used)
        disk_usage['available'].append(available)
        disk_usage['usage'].append(usage)
    return disk_usage

#读取diskstat
def read_diskstats():
    disk_num = 0
    #这个文件用于显示磁盘、分区和统计信息:sda为整个硬盘的统计信息
    with open('/proc/diskstats','r') as f:
        for line in f.readlines():
            data = line.split()
            if data[2].startswith('sda'):
                disk_active['I/O_oper_time'].append(int(data[-6])) #I/O操作花费毫秒数
                sector['read_sector'].append(int(data[5]))                   #读扇区次数
                sector['write_sector'].append(int(data[9]))                  #写扇区次数
                re_wr_num['read_num'].append(int(data[3]))           #读完成次数
                re_wr_num['write_num'].append(int(data[7]))          #写完成次数
                re_wr_time['read_time'].append(int(data[6]))           #读操作花费毫秒数
                re_wr_time['write_time'].append(int(data[10]))       #写操作花费毫秒数
                disk_num += 1
        disk_number['disk_num'] = disk_num
        list_disk = [disk_active,sector,re_wr_num,re_wr_time,disk_number]
    return list_disk

五、进程模块

部分代码如下:
procproc.py

import os
from .process.process import Process


class Processes:
    PROC_ROOT = "/proc/"

    def __init__(self):
        self.process = []
        self.__process = []

    def __clear(self):
        self.process.clear()
        self.__process.clear()

    def clear(self):
        self.__clear()

    def to_dict(self):
        self.process.clear()
        for p in self.__process:
            d = p.to_dict()
            if d is None:
                continue
            self.process.append(d)
        return self.process

    def refresh(self):

        try:
            flist = os.listdir(Processes.PROC_ROOT)
            try:
                iter_proc = iter(self.__process)
                no_more = False
                last_proc = None
                for p in flist:
                    if not p.isnumeric():
                        continue

                    if last_proc is None:
                        if not no_more:
                            try:
                                last_proc = next(iter_proc)
                            except StopIteration:
                                no_more = True
                                last_proc = Process()
                        else:
                            last_proc = Process()

                    if not last_proc.read_process(int(p)):
                        continue

                    if no_more:
                        self.__process.append(last_proc)

                    last_proc = None
            except Exception:
                return False
            else:
                return True
        except Exception:
            return False


if __name__ == '__main__':
    a = Processes()
    a.refresh()
    print(a.to_dict()['uid'])

process.py

   def __parse_cmdline(self):
        if len(self.__cmdline) > 0:
            self.cmdline = self.__cmdline[:-1]
        else:
            self.cmdline = self.__cmdline
        return True

    def __get_cmdline(self, root_path):
        cmdline = None
        path = root_path + "cmdline"

        cmdline = Process.open_and_readline(path)

        if cmdline is None:
            return False
        self.__cmdline = cmdline
        return True

    def __parse_stat(self):
        try:
            value = self.__stat.split(' ')
            if value[2].endswith(')'):
                value[1] = value[1] + ' ' + value[2]
                value.pop(2)

            self.__comm = value[1]
            self.comm = self.__comm[1:-1]
            self.__state = value[2]
            if self.__state in Process.STATE2STR.keys():
                self.state = Process.STATE2STR[self.__state]
            else:
                self.state = self.__state
            self.stime = value[13]
            self.utime = value[14]
            self.cputime = int(self.stime) + int(self.utime)
            self.priority = int(value[17])
            self.nice = int(value[18])
            self.__starttime = value[21]
            self.starttime = Process.tick2strtime(int(self.__starttime))
            self.__rss = value[23]
            self.rss = int(value[23]) * PAGE_SIZE
            if self.rss == 0:
                self.rss = 'N/A'
            elif self.rss / 1024 > 0.5:
                self.rss /= 1024
                if self.rss / 1024 > 0.5:
                    self.rss /= 1024
                    if self.rss / 1024 > 0.5:
                        self.rss = round(self.rss / 1024, 2)
                        self.rss = str(self.rss) + "GB"
                    else:
                        self.rss = round(self.rss, 2)
                        self.rss = str(self.rss) + "MB"
                else:
                    self.rss = round(self.rss, 2)
                    self.rss = str(self.rss) + "KB"
            else:
                self.rss = round(self.rss, 2)
                self.rss = str(self.rss) + "B"
            self.rt_priority = int(value[39])

            return True
        except Exception:
            return False

    def __get_stat(self, root_path):
        stat = None
        path = root_path + "stat"

        stat = Process.open_and_readline(path)

        if stat is None or len(stat) < 103:
            return False
        self.__stat = stat
        return True

    def __get_uid(self, root_path):
        try:
            stat = os.stat(root_path)
            self.uid = stat.st_uid
            return True
        except Exception:
            return False

    def to_dict(self):

        if self.pid == Process.INVAL_PID:
            return None

        self.__parse_cmdline()
        self.__parse_stat()
        r = {}
        for k, v in self.__dict__.items():
            if k.startswith('_'):
                continue
            if hasattr(v, "__str__"):
                r[k] = str(v)
            elif hasattr(v, "to_dict"):
                r[k] = v.getdict()
            else:
                r[k] = None
        return r

六、图形化界面

在这里插入图片描述在这里插入图片描述在这里插入图片描述
在这里插入图片描述
部分代码:

from tkinter import *
from tkinter import messagebox
from tkinter.ttk import *
from frame_power import *
from frame_option import *
from frame_process import *


class Application(Tk):
	def __init__(self, *args, **kw):
		super().__init__()
		self.wm_title('Linux Resource Monitor')
		
		# self.title('manager')
		self.geometry('1000x600')
		
		self.fresh_time = 250
		style = Style()
		style.configure('BW.TLabel', bg='black', font=('Fira-Code','16'), width=8, height=10)
		# init Frame
		self.frame_showing = None
		self.frame_option = Frame_option(self)
		self.frame_process = Frame_process(self)
		self.frame_power = Frame_power(self)
		
		self.frame_option.button_power = Button(self.frame_option, text='Performance', command=lambda: self.switch('power'))
		self.frame_option.button_process = Button(self.frame_option, text='Process', command=lambda: self.switch('process'))
	
		self.frame_option.button_process.grid(row=0, column=0)
		self.frame_option.button_power.grid(row=0, column=1)
		
		
		self.__init_ui()
		self.refresh_info()
		self.mainloop()
		# self.mainloop()
	
	def __init_ui(self):
		self.frame_option.pack(side=TOP, fill=X)
		self.frame_process.pack(side=TOP, fill=BOTH, expand=TRUE)
		self.frame_showing = self.frame_process
	
	def refresh_info(self):
		print(self.frame_showing)
		if self.frame_showing is self.frame_process:
			self.fresh_time = 2000
			self.frame_process.refresh_info()
		if self.frame_showing is self.frame_power:
			self.fresh_time = 250
			self.frame_power.refresh()
		
		self.after(self.fresh_time, lambda: self.refresh_info())
	
	def switch(self, frame_type):
		print(self.frame_showing, self.frame_power, self.frame_process)
		if frame_type == 'power' and self.frame_showing is not self.frame_power:
			self.frame_showing.pack_forget()
			self.frame_power.pack(side=TOP, fill=BOTH, expand=TRUE)
			self.frame_showing = self.frame_power
		if frame_type == 'process' and self.frame_showing != self.frame_process:
			self.frame_showing.pack_forget()
			self.frame_process.pack(side=TOP, fill=BOTH, expand=TRUE)
			self.frame_showing = self.frame_process

完整代码点这里

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

手可摘辰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值