在Linux上要获取进程的信息,需要读取/proc/进程id/中的文件,如果只是读一个进程还好,如果要读取很多进程,或者说像进程管理器一样要获取所有进程的信息就有点麻烦了。总不能按1-1000一个一个的遍历,效率太低。此时可以使用Linux中对目录进行操作的函数opendir(),readdir()。
转自http://www.liweifan.com/2012/05/13/linux-system-function-files-operation/
首先说说DIR这一结构体,以下为DIR结构体的定义:
struct __dirstream { void *__fd; char *__data; int __entry_data; char *__ptr; int __entry_ptr; size_t __allocation; size_t __size; __libc_lock_define (, __lock) }; typedef struct __dirstream DIR;
DIR结构体类似于FILE,是一个内部结构,以下几个函数用这个内部结构保存当前正在被读取的目录的有关信息(摘自《UNIX环境高级编程(第二版)》)。函数 DIR *opendir(const char *pathname),即打开文件目录,返回的就是指向DIR结构体的指针,而该指针由以下几个函数使用:
struct dirent *readdir(DIR *dp); void rewinddir(DIR *dp); int closedir(DIR *dp); long telldir(DIR *dp); void seekdir(DIR *dp,long loc);
关于DIR结构,我们知道这么多就可以了,没必要去再去研究他的结构成员。
接着是dirent结构体,首先我们要弄清楚目录文件(directory file)的概念:这种文件包含了其他文件的名字以及指向与这些文件有关的信息的指针(摘自《UNIX环境高级编程(第二版)》)。从定义能够看出,dirent不仅仅指向目录,还指向目录中的具体文件,readdir函数同样也读取目录下的文件,这就是证据。以下为dirent结构体的定义:
struct dirent { long d_ino; /* inode number 索引节点号 */ off_t d_off; /* offset to this dirent 在目录文件中的偏移 */ unsigned short d_reclen; /* length of this d_name 文件名长 */ unsigned char d_type; /* the type of d_name 文件类型 */ char d_name [NAME_MAX+1]; /* file name (null-terminated) 文件名,最长255字符 */ }
然后是怎么使用它读取进程信息。可以用这些函数来读取/proc下的文件夹,然后做一个判断,只要文件夹的名字开头是1-9的,就进入目录读取其中的status文件,然后输出信息。
代码
#include <stdio.h> #include <dirent.h> #include <unistd.h> #include <stdlib.h> typedef struct{ pid_t pid; char name[256];//进程名称 int vmsize;//虚拟内存信息 }proc_info_st;//保存读取的进程信息 #define PROC_NAME_LINE 1//名称所在行 #define PROC_PID_LINE 4//pid所在行 #define PROC_VMSIZE_LINE 12//虚拟内存所在行 #define BUFF_LEN 1024 //行缓冲区的长度 #ifndef TRUE # define TRUE 1 #endif #ifndef FALSE # define FALSE 0 #endif void read_proc(proc_info_st* info,const char* c_pid);//读取进程信息 int read_line(FILE* fp,char* buff,int b_l,int l);//读取一行 int main() { //打开目录 DIR *dir; struct dirent *ptr; if (!(dir = opendir("/proc"))) return 0; //读取目录 while (ptr = readdir(dir)) {//循环读取出所有的进程文件 if (ptr->d_name[0] > '0' && ptr->d_name[0] <= '9') { //获取进程信息 proc_info_st info; read_proc(&info,ptr->d_name);//读取信息 printf("pid:%d\npname:%s\nvmsize:%d\n",info.pid,info.name,info.vmsize); printf("\n\n");//再空两行 } } } /************************************************** **说明:根据进程pid获取进程信息,存放在proc_info_st结构体中 ** **输入: ** /proc_info_st* info 返回进程信息 ** /char* c_pid 进程pid的字符串形式 ** ** ** *************************************************/ void read_proc(proc_info_st* info,const char* c_pid) { FILE* fp = NULL; char file[512] = {0}; char line_buff[BUFF_LEN] = {0};//读取行的缓冲区 sprintf(file,"/proc/%s/status",c_pid);//读取status文件 if (!(fp = fopen(file,"r"))) { printf("read %s file fail!\n",file); return; } char name[32]; //先读取进程名称 if (read_line(fp,line_buff,BUFF_LEN,PROC_NAME_LINE)) { sscanf(line_buff,"%s %s",name,(info->name)); } fseek(fp,0,SEEK_SET);//回到文件头部 //读取进程pid if (read_line(fp,line_buff,BUFF_LEN,PROC_PID_LINE)) { sscanf(line_buff,"%s %d",name,&(info->pid)); } fseek(fp,0,SEEK_SET);//回到文件头部 //读取进程vmsize if (read_line(fp,line_buff,BUFF_LEN,PROC_VMSIZE_LINE)) { sscanf(line_buff,"%s %d",name,&(info->vmsize)); } fclose(fp); } /************************************************** **说明:读取文件的一行到buff ** **输入: ** /FILE* fp 文件指针 ** /char* buff 缓冲区 ** /int b_l 缓冲区的长度 ** /l 指定行 ** **输出: ** /true 读取成功 ** /false 读取失败 *************************************************/ int read_line(FILE* fp,char* buff,int b_l,int l) { if (!fp) return FALSE; char line_buff[b_l]; int i; //读取指定行的前l-1行,转到指定行 for (i = 0; i < l-1; i++) { if (!fgets (line_buff, sizeof(line_buff), fp)) { return FALSE; } } //读取指定行 if (!fgets (line_buff, sizeof(line_buff), fp)) { return FALSE; } memcpy(buff,line_buff,b_l); return TRUE; }