文章目录
0. 引言
Linux系统提供了/proc
文件系统,通过这个文件系统,用户可以获取当前运行的进程的详细信息,包括CPU和内存使用情况。每个进程都有一个独立的目录,命名为其进程ID(PID),而在这些目录中有多个文件存储着进程的状态信息。
本文将介绍如何在Linux系统上编写一个简单的C++程序,来获取指定进程(例如进程名称为sshd
)的CPU和内存使用情况。
1. 进程信息获取
在获取进程信息时,我们主要关注以下几个文件:
/proc/[PID]/stat
:该文件包含进程的状态信息,包括CPU时间。/proc/[PID]/status
:该文件包含进程的内存使用情况。/proc/[PID]/comm
:该文件包含进程的名称。
2. 实现
2.1 代码
#include <dirent.h>
#include <sys/types.h>
#include <unistd.h>
#include <algorithm>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <memory>
#include <array>
struct sysinfo {
std::string os;
std::string cpu;
std::string ram;
};
struct process_info {
int pid;
std::string name;
double cpu_usage;
std::string mem_usage;
};
std::string exec_command(const char* cmd) {
std::array<char, 128> buffer;
std::string result;
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd, "r"), pclose);
if (!pipe) {
throw std::runtime_error("popen() failed!");
}
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
result += buffer.data();
}
// Remove trailing newline
if (!result.empty() && result.back() == '\n') {
result.pop_back();
}
return result;
}
sysinfo get_sysinfo() {
sysinfo sys;
sys.os = "Linux";
try {
sys.cpu = exec_command(
"cat /proc/cpuinfo | grep 'model name' | uniq | sed 's/model name[[:blank:]]*:[[:blank:]]*//' | awk 1 ORS=' '");
sys.ram = exec_command(
"cat /proc/meminfo | grep 'MemTotal' | sed 's/MemTotal:[[:blank:]]*//' | awk '{$1=$1/1024^2; print "
"$1,\"GB\";}' | awk 1 ORS=' '");
} catch (const std::runtime_error& e) {
std::cerr << "Failed to get system information: " << e.what() << std::endl;
}
return sys;
}
std::vector<process_info> get_process_info(const std::vector<std::string>& process_names) {
std::vector<process_info> processes;
DIR* dir = opendir("/proc");
struct dirent* entry;
while ((entry = readdir(dir)) != nullptr) {
if (entry->d_type == DT_DIR) {
std::string pid_str(entry->d_name);
if (std::all_of(pid_str.begin(), pid_str.end(), ::isdigit)) {
int pid = std::stoi(pid_str);
std::string comm_file = "/proc/" + pid_str + "/comm";
std::ifstream comm_stream(comm_file);
std::string name;
std::getline(comm_stream, name);
if (std::find(process_names.begin(), process_names.end(), name) != process_names.end()) {
process_info proc;
proc.pid = pid;
proc.name = name;
std::string stat_file = "/proc/" + pid_str + "/stat";
std::ifstream stat_stream(stat_file);
if (stat_stream.is_open()) {
std::string ignore;
double utime, stime;
for (int i = 0; i < 13; ++i) {
stat_stream >> ignore;
}
stat_stream >> utime >> stime;
long total_time = utime + stime;
long hertz = sysconf(_SC_CLK_TCK);
proc.cpu_usage = (total_time / (double)hertz);
std::string status_file = "/proc/" + pid_str + "/status";
std::ifstream status_stream(status_file);
std::string line;
while (std::getline(status_stream, line)) {
if (line.find("VmRSS:") == 0) {
proc.mem_usage = line.substr(6);
break;
}
}
processes.push_back(proc);
}
}
}
}
}
closedir(dir);
return processes;
}
int main() {
sysinfo sys = get_sysinfo();
std::cout << "Operating System: " << sys.os << std::endl;
std::cout << "CPU: " << sys.cpu << std::endl;
std::cout << "RAM: " << sys.ram << std::endl;
std::vector<std::string> process_names = {"sshd"};
std::vector<process_info> processes = get_process_info(process_names);
std::cout << "\nProcess List:" << std::endl;
for (const auto& proc : processes) {
std::cout << "PID: " << proc.pid << ", Name: " << proc.name << ", CPU Usage: " << proc.cpu_usage
<< " sec, Memory Usage: " << proc.mem_usage << std::endl;
}
return 0;
}
2.2 代码解析
-
结构体定义:
sysinfo
:用于存储系统信息,包括操作系统、CPU和内存信息。process_info
:用于存储进程信息,包括PID、名称、CPU使用时间和内存使用情况。
-
获取系统信息:
get_sysinfo
函数获取系统的操作系统、CPU和内存信息。
-
获取特定进程信息:
get_process_info
函数遍历/proc
文件系统,查找指定名称的进程,并提取其PID、CPU和内存使用情况。
-
主函数:
- 调用系统信息和进程信息函数,并打印结果。
2.3 运行效果
g++ -o mytest mytest.cpp -std=c++14
编译并运行程序后:
./mytest
Operating System: Linux
CPU: AMD Ryzen 5 3500U with Radeon Vega Mobile Gfx
RAM: 3.77756 GB
Process List:
PID: 1331, Name: sshd, CPU Usage: 0.01 sec, Memory Usage: 7808 kB
PID: 1332, Name: sshd, CPU Usage: 0.03 sec, Memory Usage: 7792 kB
PID: 1446, Name: sshd, CPU Usage: 2.14 sec, Memory Usage: 6956 kB
PID: 1495, Name: sshd, CPU Usage: 0.02 sec, Memory Usage: 8688 kB
PID: 1550, Name: sshd, CPU Usage: 0.67 sec, Memory Usage: 7344 kB
2.4 实现方式优劣势
优势
- 简单易读 :通过执行系统命令获取信息,代码更简洁,易于理解和维护。
- 复用现有工具 :利用已有的系统命令,如
cat
和grep
,不需要自己解析复杂的文件内容。
劣势
- 效率低下 :每次获取信息都需要创建新进程执行命令,带来了额外的系统开销。
- 依赖外部命令 :依赖于系统上存在特定的命令,并且这些命令的输出格式不能保证在所有系统上都一致。
- 安全性问题 :使用
popen
执行命令可能带来安全风险,特别是在处理不受信任的输入时。
考虑以上方案的缺陷,更推荐如下文章的实现 Linux编程:进程保活,自动重启与资源监控的实现.