环境搭建:
-
主机:Windows10+VirtualBox 6.1
-
操作系统 Unbuntu 20.10 (内核版本:5.8.0-44-generic)
打印Linux系统进程树并可视化
思路:利用pstree -p 查询进程树,并将其保存在txt中,实现线程树的查看和打印;或使用ps选项;或利用/proc目录将每一个进程的子进程和父进程及其他一些信息保存在txt中(采用中序遍历的方式),将文件用java进行处理,利用前端实现可视化的界面窗口。
法一,通过pstree -p 预览进程树:
利用pstree -p > ~/01.txt 重定向到01.txt中。实现将进程内容储存到txt文件中,从而实现对进程地存储。
法二,ps -ef 选项
实现效果:
法三,中序遍历/proc目录,使用java处理数据后前端显示
遍历/proc目录代码:
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#include<sys/types.h>
#include<netdb.h>
#include<pthread.h>
#include<unistd.h>
#include<dirent.h>
char default_path[1024]="/proc/";
int s=0;
typedef struct file_info
{
int pid; // 进程号
int ppid; // 父进程号
char name[1024]; // 进程名称
int flag; //进程标志
int rec; //打印进程树时用来标志是几级进程的
}info;
int my_getpid(char *str) // 获得进程号
{
int len=strlen(str);
char num[10];
int i,j,ret;
if(strncmp(str,"Pid",3)==0)
{
for(i=0;i<len;i++)
{
if(str[i]>='0'&&str[i]<='9')
break;
}
for(j=0;j<len-i;j++)
{
num[j]=str[i+j];
}
ret=atoi(num);
}
else ret=0;
return ret;
}
int my_getppid(char *str) // 获得父进程号
{
int len=strlen(str);
char num[10];
int i,j,ret;
if(strncmp(str,"PPid",4)==0)
{
for(i=0;i<len;i++)
{
if(str[i]>='0'&&str[i]<='9')
break;
}
for(j=0;j<len-i;j++)
{
num[j]=str[i+j];
}
ret=atoi(num);
}
else ret=0;
return ret;
}
int child_exist(info *file,int count,int ppid) //判断是否存在子进程
{
int i;
for(i=0;i<count;i++)
{
if(file[i].flag==0&&file[i].ppid==ppid)
return 1;
}
return 0;
}
void print_pstree(info *file,int count,int ppid,int rec) // 打印进程树,用递归方法,中序遍历
{
int i,j,k;
for(i=0;i<count;i++)
{
if(file[i].flag==0&&file[i].ppid==ppid)
{
file[i].rec=rec+1;
file[i].flag=1;
for(k=0;k<rec;k++)
printf(" ");
printf("%d=>%s\n",file[i].pid,file[i].name);
print_pstree(file,count,file[i].pid,file[i].rec);
}
}
}
int main()
{
int i,j,k,total,s1,s2,count,t;
char str[1024],dir[1024];
struct dirent **namelist;
strcpy(dir,default_path);
total=scandir(dir,&namelist,0,alphasort);
printf("path=%s,total=%d\n",dir,total);
for(i=0;i<total;i++)
{
strcpy(str,namelist[i]->d_name);
if(str[0]>='0'&&str[0]<='9')
count++;
}
printf("进程数:%d\n",count);
info file[1024];
i=0;
t=0;
while(i<total)
{
FILE *fp;
char path[1024],name[1024];
int pid,ppid;
strcpy(str,namelist[i]->d_name);
strcpy(path,default_path);
if(str[0]>='0'&&str[0]<='9')
{
strcat(path,str);
strcat(path,"/status");
fp=fopen(path,"r");
while(!feof(fp))
{
fgets(str,1024,fp);
//pid
if((s1=my_getpid(str))!=0)
pid=s1;
//ppid
if((s2=my_getppid(str))!=0)
ppid=s2;
//name
if(strncmp(str,"Name",4)==0)
{
for(j=4;j<strlen(str);j++)
{
if(str[j]>='a'&&str[j]<='z')
break;
}
for(k=j;k<strlen(str);k++)
{
name[k-j]=str[k];
}
name[k-j-1]='\0';
}
file[t].pid=pid;
file[t].ppid=ppid;
strcpy(file[t].name,name);
}
fclose(fp);
t++;
}
i++;
}
memset(&file->flag,0,count);
memset(&file->rec,0,count);
print_pstree(file,count,0,0);
}
Java代码:
import javax.swing.*;
import java.io.*;
import java.io.File;
public class txtOperation {
public static void main(String[] args) {
File file = new File("txt/01.txt");
int lineNumber=0;
String[] ls= new String[10000];
StringBuilder result = new StringBuilder();
try{
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));//构造一个BufferedReader类来读取文件
String s = null;
while((s = br.readLine())!=null){//使用readLine方法,一次读一行
lineNumber++;
ls[lineNumber]=s.toString();
result.append( System.lineSeparator() + s);
}
br.close();
}catch(Exception e) {
e.printStackTrace();
}
foundp fp=new foundp(ls,lineNumber);
fp.create();
fp.f(1);
System.out.print("`[");
for(int i=1;i<=lineNumber;i++)
{
System.out.print("{");
System.out.print("\"pid\":"+fp.p[i].getPid()+","+"\"pname\":\""+fp.p[i].getName()+"\",");
System.out.print("\"son\":[");
for (int j = 1; j <=fp.p[i].getSonNumber(); j++) {
if(j!=fp.p[i].getSonNumber())
System.out.print("\""+fp.p[i].getSon(j)+"\",");
else System.out.print("\""+fp.p[i].getSon(j)+"\"");
}
System.out.print("]");
if(i!=lineNumber)
System.out.println("},");
else System.out.println("}");
}
System.out.print("]`");
}
}
class pthread{
private String pid;
private String name;
private int sonNumber=0;
private String[] son=new String[10000];
public String getPid() {
return pid;
}
public void setPid(String pid) {
this.pid = pid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSonNumber() {
return sonNumber;
}
public void setSonNumber(int sonNumber) {
this.sonNumber += sonNumber;
}
public String getSon(int j) {
return son[j];
}
public void setSon(String son) {
this.son[this.sonNumber] = son;
}
}
class foundp {
String[] ls= new String[500];
int lineNumber;
public foundp(String[] ls,int lineNumber) {
this.ls = ls;
this.lineNumber=lineNumber;
}
pthread[] p= new pthread[10000];
public void create()
{
for(int pi=0;pi<10000;pi++)
p[pi]=new pthread();
}
public String f(int i){
if(i>lineNumber)
return null;
int pi=0,pj;
while(ls[i].charAt(pi)==' ')
pi++;
pj=pi;
while(ls[i].charAt(pj)!='=')
pj++;
p[i].setPid(ls[i].substring(pi,pj));
p[i].setName(ls[i].substring(pj+2));
if(i==lineNumber)
{
return p[i].getName();
}
else {
int sonp=i+1;
while (sonp<=lineNumber)
{
int sonpi=0;
while(ls[sonp].charAt(sonpi)==' ') sonpi++;
if(sonpi==(pi+1))
{
Integer ps=sonp;
p[i].setSonNumber(1);
int sonpj=sonpi;
while(ls[sonp].charAt(sonpj)!='=')
sonpj++;
p[i].setSon(ls[sonp].substring(sonpj+2));
}
else{
if(sonpi<=pi) break;
}
sonp++;
}
f(i+1);
}
return p[i].getName();
}
}
然后利用json文件使用html+css+jss实现网页端的进程查看管理:采用grid布局,利用js获取点击事件,和innerHTML更改pid pname的操作
网页截图: