C语言环境读取/proc目录的进程信息

本文介绍如何利用Linux的/proc文件系统来获取进程信息。通过C语言编程实现读取进程的状态、用户名、命令行参数等关键数据,并将这些信息转换为JSON格式输出。

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

通过/proc目录可以获取所有的进程信息。

需要注意的是 readlink系统调用不会追加0到字符串结尾,并且字符串的最大长度需要时读取长度+1,便于添加0结束字符串。

 

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>


typedef struct {
    int Pid;
    int Ppid;
    char Name[128];
    char Username[32];
    int Effecitveuid;
    char Exe[128];
    char Cmdline[1024];
    char Fd[1024];
}proc ;


proc g_proc;


static inline char* next_line( char *str ) {
    int i = 0;
    while( str[i] != '\n' ) {
        if( str[i] == 0 ) {
            return str+i;
        }
        i++;
    }
    i++; //skip the char '\n'
    return str+i;
}

proc* get_proc( int pid ) 
{
    char filename[128];
    char buff[1024];
    char key[16];
    char val0[16], val1[16], val2[16], val3[16]; 
    int str_len;
    FILE *fp;
    int i, count;
    int ret;
    proc* p = &g_proc;
    struct passwd *pws;

    sprintf(filename, "/proc/%d/status", pid);
    fp = fopen(filename, "r");
    if( fp != NULL ){
        str_len = fread(buff, 1, 1024, fp);
        if( str_len > 0) {
            char *next, *curr;
            curr = buff;
            next = next_line(curr);
            count = 0;
            while(next != curr) {
                *(next-1) = 0;
                ret = sscanf(curr, " %s %s %s %s %s ", key, val0, val1, val2, val3);
                if( strcmp(key, "Pid:") == 0 ) {
                    p->Pid = atoi(val0);
                    count++;
                }else if( strcmp(key, "Name:") == 0 ) {
                    strcpy(p->Name, val0);
                    count++;
                }else if( strcmp(key, "PPid:") == 0 ) {
                    p->Ppid = atoi(val0);
                    count++;
                }else if( strcmp(key, "Uid:") == 0 ) {
                    p->Effecitveuid= atoi(val1);
                    int uid = atoi(val0);
                    pws = getpwuid(uid);
                    strcpy(p->Username, pws->pw_name);
                    count++;
                }else if( count >= 3) {
                    break;
                }

                curr = next;
                next = next_line(curr);
            }
            fclose(fp);
        }
    }else{
        return NULL;
    }
    
    p->Cmdline[0] = 0;
    sprintf(filename, "/proc/%d/cmdline", pid);
    fp = fopen(filename, "r");
    if( fp != NULL ) {
        str_len = fread(p->Cmdline, 1, 1024, fp);
        i = 0;
        while(i < str_len-1) {
            if(p->Cmdline[i] == 0) {
                p->Cmdline[i] = ' ';
            }
            i++;
        }
        fclose(fp);
    }

    p->Exe[0] = 0;
    sprintf(filename, "/proc/%d/exe", pid);
    str_len = readlink(filename, p->Exe, 128);
    if( str_len > 0 ) {
        i = 0;
        while(i < str_len) {
            if(p->Exe[i] == 0) {
                p->Exe[i] = ' ';
            }
            i++;
        }
        p->Exe[str_len] = 0;
    }
    
    p->Fd[0] = 0;
    strcpy(p->Fd, "[");
    str_len = 1;
    i = 0;
    while( i < 3 ) {
        sprintf(filename, "/proc/%d/fd/%d", pid, i);
        ret = readlink(filename, buff, 128);
        if( ret > 0 ) {
            buff[ret] = 0;
            str_len += sprintf(p->Fd+str_len, "\"%s\",", buff);
        }
        i++;

    }
    if( p->Fd[str_len-1] == ',') {
        p->Fd[str_len-1] = ']';
    }else {
        strcat(p->Fd, "]");
    }
    return p;
}

int proc2json(proc *p, char *buff) 
{
   int len = 0;
   len += sprintf(buff, "{");
   len += sprintf(buff+len, "\"%s\":%d,", "Pid", p->Pid);
   len += sprintf(buff+len, "\"%s\":\"%s\",", "Name", p->Name);
   len += sprintf(buff+len, "\"%s\":%d,", "Ppid", p->Ppid);
   len += sprintf(buff+len, "\"%s\":\"%s\",", "Username", p->Username);
   len += sprintf(buff+len, "\"%s\":%d,", "Effecitveuid", p->Effecitveuid);
   len += sprintf(buff+len, "\"%s\":\"%s\",", "Exe", p->Exe);
   len += sprintf(buff+len, "\"%s\":\"%s\",", "Cmdline", p->Cmdline);
   len += sprintf(buff+len, "\"%s\":%s", "Fd", p->Fd);
   len += sprintf(buff+len, "}");
   return len;
}

void main() 
{
    int i = 0;
    int ret;
    proc *p;
    char buff[2048];
    while(i++ < 60000) {
        p = get_proc(i);
        if(p) {
            ret = proc2json(&g_proc, buff);
            printf("%s\n", buff);
        }
    }
}

 

在Linux下,可以通过`/proc/stat`文件获取到系统的CPU占用率。CPU占用率通常是通过计算用户态时间和系统态时间来得到的,这包括`utime`(用户进程CPU时间)和`stime`(系统进程CPU时间)两个字段。以下是一个简单的C语言示例,展示如何计算CPU平均占用率: ```c #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> // 需要获取pid_t类型 #include <fcntl.h> #include <linux/time.h> // 包含time_t结构 #define PROC_STAT_FILE "/proc/stat" #define INTERVAL_SECONDS 1 // 计算间隔时间,这里假设1秒 double get_cpu_usage(pid_t pid) { struct tms time_info; clock_t start_time = clock(); while (clock() - start_time < INTERVAL_SECONDS * CLOCKS_PER_SEC) { if (getline(&line, &line_len, fopen(PROC_STAT_FILE, "r")) == -1) { perror("Failed to read from /proc/stat"); return -1; } // 简单地找到utime和stime的索引位置,注意实际文件格式可能会有变动 char *utime_str = strstr(line, "utime:"); char *stime_str = strstr(line, "stime:"); if (utime_str && stime_str) { utime_str += 6; // 跳过"utime:" stime_str += 6; // 跳过"stime:" double utime_sec = atof(utime_str); double stime_sec = atof(stime_str); // 系统占用时间 = 用户占用时间 + 系统占用时间 double total_cpu_time = utime_sec + stime_sec; // 如果进程还在运行,则累加其CPU使用时间 if (pid > 0) total_cpu_time += sysconf(_SC_CLK_TCK) * (getrusage(RUSAGE_SELF, &time_info).ru_utime.tv_sec + getrusage(RUSAGE_SELF, &time_info).ru_stime.tv_sec); return total_cpu_time / INTERVAL_SECONDS; } } return -1; // 如果未在指定时间内读取到数据,返回错误值 } int main() { pid_t my_pid = getpid(); // 获取当前进程PID double cpu_usage = get_cpu_usage(my_pid); if (cpu_usage >= 0) printf("Current CPU usage (in seconds): %.2f%%\n", cpu_usage * 100); else fprintf(stderr, "Failed to calculate CPU usage.\n"); return 0; } ``` 此代码片段展示了获取自身CPU占用率的基本思路,但请注意,实际应用中可能需要处理更多的边缘情况,比如读取失败、进程结束等。同时,由于`getrusage`用于实时获取进程CPU时间,对于长时间运行的应用,这种计算方法可能不够准确,因为它基于的是进程创建以来的时间,而非实时计数。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值