读取linux /proc/文件信息,用GTK编程实现简单的系统管理器

本文介绍如何使用GTK图形界面库来读取Linux /proc目录下的系统信息,包括CPU、内存、进程等。通过分析/proc文件的结构,程序逐行读取并筛选出有用信息展示在GUI上。读者将了解如何打开和解析/proc文件,以及如何设计算法过滤无用数据。最后,文章提供了一个简单的系统管理器的实现和界面截图。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

源程序附最后(也可直接打包下载http://download.csdn.net/detail/creazyapple/4088149

要求:

理解和分析/proc文件

内容

了解/proc文件的特点和使用方法。

监控系统状态,显示系统中若干部件的使用情况。

用图形界面显示系统监控状态。


相关原理:

用户和应用程序可以通过/proc得到系统的信息,并可以改变内核的某些参数。由于系统的信息是动态改变的,所以用户或应用程序读取proc文件时,proc文件系统是动态从系统内核读出所需信息并提交的。

我们要显示系统信息,只需进行相应的文件操作。首先打开相应的文件,读取所需要的信息,将其写入一个缓冲区中,然后将缓冲区的内容加到Gtk的相应的控件上面去,最后将控件组合显示即可

/proc/文件结构参考:http://blog.csdn.net/ubuntulover/article/details/4449787

比如我们如果要读取cpu信息,可以在控制台下输入命令:cat /proc/cpuinf



要得到内存信息,可以输入命令:cat /proc/meminfo

这只是冰山一角,仅此我们已经看到/proc目录下文件内容之丰富。

要想编程读取这些信息,首先我们要了解/proc结构,了解其各种信息的排布,然后就像读普通文件一样将其筛选出来。

比如,查看系统的cpu频率,属于cpu信息:more /proc/cpuinfo         (注,命令more 和cat功能相似,都是显示一个文件的内容)

其排布为如下:



我们也就知道,cpuinf文件中,一种信息放一行,因此我们一行一行的遴选信息。

首先需将cpuinf文件读出来,

	fp = fopen("/proc/cpuinf", "r");
	/* 从fp中读取sizeof(buffer)块数据放入buffer */
	buf = fread(buffer, 1, sizeof(buffer), fp);
	fclose(fp);

然后进行字符串匹配,找到含有“cpu MHz”这个字符串的一行,读出来即可。

其它如模块信息、内存信息,类似处理,字要你了解了其结构,就可以方便的读出来

所以关键有3点:1、你知道信息在哪里;2、你看到了信息的排列方式;3、设计算法剔除无用信息。


而对于进程信息,稍复杂。

我们先看看进程信息放在哪里的:首先进入 /proc 目录并查看该目录下的文件:


蓝色的是目录(所谓的文件夹),绿色的是文件,文件中有cpuinf、meminfo等,我们之前已经看过。现在看看那些蓝色的以数字为名的文件夹,他们正是保存进程信息的!

目录1存储的是PID为1的进程的信息,目录2存储的是PID为2的进程的信息……

我们试着进入这些目录看看!


里面有一些目录和文件,其中有个status文件,打开看看:

看到了吧,很清晰地罗列出了进程1的信息,名字是init,状态Sleeping ,PID是1……

由此得知,要读取所有进程的信息列表,我们需要循环打开/proc文件夹下所有以数字命名的目录。

大致过程为:

	while ((ptr = readdir(dir)) != NULL)
	{
		if ((ptr->d_name[0] >= '0') && (ptr->d_name[0] <= '9')) //打开以数值命名的目录
                {
			sprintf(path, "/proc/%s/status", ptr->d_name); //将此文件的全部路径写入name中
			//打开这个文件,并且从中读取到有用的信息放在相应的数组中
			fd = open(path, O_RDONLY);
			read(fd, store, sizeof(store));    
                        ……
                        读取信息                                
                        ……
			close(fd); 
                }
	}
	closedir(dir);

好了,现在弄清楚了原理,就可以动手实现了。但是需要一个界面呀,这里我们继续用GTK来画界面。

关于GTK这里就不多说了。

最后实现界面截图:


杀死进程:

刷新列表:


最后,附上源程序。共11个文件,将其放入一个文件夹下,编译命令:gcc -o sb *.c `pkg-config --cflags --libs gtk+-2.0`(当然首先得配置好了GTK,

参考上一篇博客 ubuntu GTK+eclipse 配置 http://blog.csdn.net/creazyapple/article/details/7290443)


/*
 *  MainWin.c
 *  SystemMonitor
 *  Created on: 2012-2-24
 *      Author: zhushengben
 */

#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <fcntl.h>
#include <dirent.h>
#include <gdk/gdkkeysyms.h>
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <cairo.h>
#include <time.h>

#define MAX  1024
#include "searchInfor.h"
#include "cpu.h"
#include "memory.h"
#include "module.h"
#include "process.h"
#include "menuBar.h"
#include "progressBar.h"
#include "showAbout.h"
#include "refresh.h"
#include "showImage.h"
int main(int argc, char ** argv)
{

	GtkWidget * window;
	GtkWidget * main_vbox;
	GtkWidget *tooltip;
	gtk_init(&argc, &argv);

	/* 主窗口 */
	window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
	tooltip = gtk_tooltips_new();
	gtk_tooltips_set_tip(tooltip, window, "系统监视器\n此软件归华中科技大学所有\n未经授权不可擅自更改",
			NULL);
	gtk_window_set_title(GTK_WINDOW(window), "System Moniter");
	gtk_window_set_opacity(GTK_WINDOW(window), 0.95); // 设置透明度函数
	//update_widget_bg(window, BACK_IMAGE);

	/* 默认窗口大小 */
	gtk_window_set_default_size(GTK_WINDOW(window), 800, 600);

	/* 窗口初始位置在屏幕最中央 */
	gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);

	/* 显示窗口 */
	gtk_widget_show(window);

	/* 创建一个纵向盒 */
	main_vbox = gtk_vbox_new(FALSE, 10);

	/* 设定这个容器和周围的间距 */
	gtk_container_set_border_width(GTK_CONTAINER(main_vbox), 5);

	/* 将这个布局容器添加到整个视窗的容器中 */
	gtk_container_add(GTK_CONTAINER(window), main_vbox);

	/* 显示该盒 */
	gtk_widget_show(main_vbox);

	createMenuBar(main_vbox);

	/* 建立多标签页notebook */
	GtkWidget *notebook = gtk_notebook_new();
	gtk_notebook_set_tab_pos((GtkNotebook *) notebook, GTK_POS_BOTTOM);
	gtk_notebook_set_show_border((GtkNotebook *) notebook, FALSE);
	/* 在纵向盒顶部添加该笔记本 */
	gtk_box_pack_end(GTK_BOX(main_vbox), notebook, TRUE, TRUE, 0);

	/* 显示该笔记本 */
	gtk_widget_show(notebook);

	/* 新建第一个标签页到notebook,用的是frame框架 */
	createCPUPage(notebook);

	/* 新建第三个标签页到notebook */
	createModPage(notebook);

	/* 新建第四个标签页到notebook */
	createProPage(notebook);

	/* 新建第五个标签页到notebook */
	/* 原来是mem模块在死循环中 */
	createMemPage(notebook);

	/* 新建第二个标签页到notebook */
	createAboutPage(notebook);

	gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), 0);
	/**************************************************/
	gtk_timeout_add(400, refresh, pdata);

	gtk_main();
	return 0;
}

/*
 *  cpu.h
 *  helloWorld
 *  Created on: 2012-2-19
 *      Author: zhushengben
 */

#ifndef CPU_H_
#define CPU_H_

GtkWidget *window;
GtkWidget *main_vbox;
GtkWidget *clist; //进程时候需要的列表
GtkWidget *clist2; //模块读取时需要的列表
GtkWidget *cpu_draw_area;
GdkPixmap *cpu_graph;
GtkWidget *pbar_cpu;

/* 全局变量 */
static gint cpuPoints[100];
static gfloat cpu_rate = 0.0;
static char PID[20];
static int selectedRow;
float zuser = 0, ztotal = 0;
typedef struct CPUinfo
{
	char modeName[50]; //line 5
	char cpuMHz[10]; //line 7
	char cacheSize[10];//line 8
	char cpuCores[10]; //line 12
	char addrSize[50]; //line 30
}*cpuInfo;

static gboolean cpu_expose_event(GtkWidget *widget, GdkEventExpose *event,
		gpointer data)
{
	gdk_draw_drawable(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(
			widget)], cpu_graph, event->area.x, event->area.y, event->area.x,
			event->area.y, event->area.width, event->area.height);
	return FALSE;
}

static gboolean cpu_configure_event(GtkWidget *widget,
		GdkEventConfigure *event, gpointer data)
{
	if (cpu_graph)
	{
		g_object_unref(cpu_graph);
	}
	cpu_graph = gdk_pixmap_new(widget->window, widget->allocation.width,
			widget->allocation.height, -1);
	gdk_draw_rectangle(cpu_graph, widget->style->white_gc, TRUE, 0, 0,
			widget->allocation.width, widget->allocation.height);
	return TRUE;
}
/* 取得cpu利用率 */
float getCpuUseRatio()
{
	FILE *fp;
	char buffer[1024];
	size_t buf;
	float useRatio;
	/* 分别为用户模式,低优先级用户模式,内核模式,空闲的处理器时间 */
	float user = 0, nice = 0, sys = 0, idle = 0, iowait = 0;

	fp = fopen("/proc/stat", "r");
	/* 从fp中读取sizeof(buffer)块数据放入buffer,每次读一块 */
	buf = fread(buffer, 1, sizeof(buffer), fp);
	fclose(fp);
	if (buf == 0)
		return 0;
	buffer[buf] == '\0';
	sscanf(buffer, "cpu %f %f %f %f %f", &user, &nice, &sys, &idle, &iowait);
	if (idle <= 0)
		idle = 0;
	useRatio = 100 * (user - zuser) / (user + nice + sys + idle - ztotal);
	if (useRatio > 100)
		useRatio = 100;
	ztotal = user + nice + sys + idle;
	zuser = user;
	cpu_rate = useRatio;
	return useRatio;
}

/* cpu标签页,显示cpu信息 */
void createCPUPage(GtkWidget* notebook)
{
	GtkWidget *label;
	GtkWidget *vbox;

	GtkWidget *frame1 = gtk_frame_new("");

	gtk_container_set_border_width(GTK_CONTAINER(frame1), 10);
	gtk_widget_set_size_request(frame1, 120, 500);
	gtk_widget_show(frame1);

	/* 将该标签页加入到notebook中 */
	gtk_notebook_append_page(GTK_NOTEBOOK(notebook), frame1, gtk_label_new(
			"CPU信息"));

	/* 在该页建议个表格,分为上下2行,一列 */
	GtkWidget *table1 = gtk_table_new(10, 10, TRUE);

	/* 将这个表添加到“cpu使用率“页 */
	gtk_container_add(GTK_CONTAINER(frame1), table1);

	/* 新建一个frame框架用于显示图表 */
	GtkWidget *CPU_frame1 = gtk_frame_new("CPU使用历史曲线");

	/* 放到表格第一行 */
	/* 这个函数的参数不懂,不好调整 */
	gtk_table_attach_defaults(GTK_TABLE(table1), CPU_frame1, 0, 8, 0, 5);
	gtk_widget_show(CPU_frame1);

	/* 现在,我们开始向屏幕绘图。
	 * 我们使用的构件是绘图区构件。
	 *一个绘图区构件本质上是一个 X 窗口,没有其它的东西。
	 *它是一个空白的画布,我们可以在其上绘制需要的东西。*/
	cpu_draw_area = gtk_drawing_area_new();

	/* 设置可以画图 */
	gtk_widget_set_app_paintable(cpu_draw_area, TRUE);

	/* 画图区默认大小 */
	gtk_drawing_area_size(GTK_DRAWING_AREA(cpu_draw_area), 40, 80);
	/* 画布添加到cpu曲线框架中 */
	gtk_container_add(GTK_CONTAINER(CPU_frame1), cpu_draw_area);
	gtk_widget_show(cpu_draw_area);
	/* 关联回调函数 */
	/* 关于各种事件不甚了解 */
	g_signal_connect(cpu_draw_area, "expose_event",
			G_CALLBACK(cpu_expose_event), NULL);
	g_signal_connect(cpu_draw_area, "configure_event", G_CALLBACK(
			cpu_configure_event), NULL);
	gtk_widget_show(cpu_draw_area);

	int i;
	for (i = 0; i < 100; i++)
	{
		/* 要取[a,b)之间的随机整数(包括a,但不包括b),使用:
		 * (rand() % (b - a)) + a */
		cpuPoints[i] = (rand() % 30 + 180);
	}

	// 	此处出现问题
	/* 不断刷新画图 */
	//	gtk_timeout_add(100, (GtkFunction) drawGraph, NULL);

	/* 取得CPU信息 */
	char modeName[50], cpuMHz[20], cacheSize[20], cpuCores[20], addrSize[50];
	char cpuBuffer[1000];

	//getCPUInfo("/proc/cpuinfo", modeName, cacheSize);
	//cpuMHz,cacheSize,cpuCores,addrSize);
	/* 不能用\t !! */

	getInforNotd("/proc/cpuinfo", "model name", modeName);
	getInforNotd("/proc/cpuinfo", "cache size", cacheSize);
	getInforNotd("/proc/cpuinfo", "cpu MHz", cpuMHz);
	getInforNotd("/proc/cpuinfo", "cpu cores", cpuCores);
	getInforNotd("/proc/cpuinfo", "address sizes", addrSize);

	/* 建一个frame在表一下半部显示cpu信息 */
	GtkWidget *frame_down = gtk_frame_new("系统信息 ");
	gtk_table_attach_defaults(GTK_TABLE(table1), frame_down, 0, 10, 5, 10);
	gtk_widget_show(frame_down);
	/* 这里必须要show表,为什么?不知到该在什么时候show什么 */
	gtk_widget_show(table1);

	/* 在该狂建建一个表格,将下半部分为1行,2列 *
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值