如何获取特定用户进程列表、处理uid_t类型及进程网络信息?
问题解决方案
一、读取/proc/status中的UID并转换为uid_t类型进行比较
/proc/[pid]/status文件里的Uid行包含四个值:真实UID、有效UID、保存设置UID、文件系统UID,格式类似:
Uid: 1000 1000 1000 1000
要和geteuid()返回的有效用户ID对比,需提取第二个值。具体实现如下:
- 从status文件逐行读取内容,提取
Uid对应的字段; - 分割字段得到有效UID的字符串值,转换为
uid_t类型(uid_t本质是无符号整数,用std::stoul或strtoul转换更安全); - 与
geteuid()的返回值比较,筛选出当前用户启动的进程。
修改后的代码片段:
ProcessInfo getInfoFromFileByPID(char pid[], const char* filename) { printf("getInfoFromFileByPID param = %s %s\n", pid, filename); char path[256]; FILE* fp; char line[256]; ProcessInfo process; uid_t current_euid = geteuid(); // 获取当前进程的有效用户ID snprintf(path, sizeof(path), filename, pid); fp = fopen(path, "r"); if (fp) { // 逐行读取避免文件内容截断 while (fgets(line, sizeof(line), fp) != NULL) { std::string str_line(line); size_t colon_pos = str_line.find(':'); if (colon_pos == std::string::npos) continue; std::string key = str_line.substr(0, colon_pos); std::string value = str_line.substr(colon_pos + 1); // 清除值前后的空白字符 value.erase(0, value.find_first_not_of(" \t\n")); value.erase(value.find_last_not_of(" \t\n") + 1); if (key == "Name") { process.Name = value; } else if (key == "Pid") { process.PID = std::stoi(value); } else if (key == "Uid") { // 分割UID的四个部分,取第二个(有效UID) std::istringstream iss(value); std::vector<std::string> uid_parts; std::string part; while (iss >> part) uid_parts.push_back(part); if (uid_parts.size() >= 2) { uid_t process_euid = static_cast<uid_t>(std::stoul(uid_parts[1])); // 对比当前用户的有效UID process.is_current_user = (process_euid == current_euid); } } } fclose(fp); return process; } return process; }
二、获取进程的IP地址、端口及目标主机名
进程的网络连接信息存放在/proc/[pid]/net/tcp(TCP连接)和/proc/[pid]/net/udp(UDP连接)文件中,每行记录一个连接,格式示例(TCP):
sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
0: 0100007F:0016 00000000:0000 0A 00000000:00000000 00:00000000 00000000 1000 0 123456
解析步骤:
- 读取对应文件,跳过首行表头;
- 分割每行字段,提取本地/远程地址(IP:端口的十六进制格式);
- 将十六进制IP转换为十进制字符串,十六进制端口转换为十进制数值;
- 用
getnameinfo函数将远程IP解析为主机名(编译时需链接-lresolv库)。
示例代码片段:
#include <netdb.h> #include <arpa/inet.h> #include <sstream> #include <vector> // 十六进制字符串转字节 unsigned char hex_to_byte(const std::string& hex) { return static_cast<unsigned char>(std::stoul(hex, nullptr, 16)); } // 十六进制IP转十进制格式(如0100007F → 127.0.0.1) std::string hex_ip_to_decimal(const std::string& hex_ip) { if (hex_ip.length() != 8) return ""; // 十六进制IP按字节反转存储,需调整顺序 unsigned char bytes[4] = { hex_to_byte(hex_ip.substr(6, 2)), hex_to_byte(hex_ip.substr(4, 2)), hex_to_byte(hex_ip.substr(2, 2)), hex_to_byte(hex_ip.substr(0, 2)) }; char ip_str[INET_ADDRSTRLEN]; inet_ntop(AF_INET, bytes, ip_str, sizeof(ip_str)); return std::string(ip_str); } // 十六进制端口转十进制 uint16_t hex_port_to_decimal(const std::string& hex_port) { return static_cast<uint16_t>(std::stoul(hex_port, nullptr, 16)); } // IP地址转主机名 std::string ip_to_hostname(const std::string& ip) { struct sockaddr_in sa; char hostname[NI_MAXHOST]; memset(&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; inet_pton(AF_INET, ip.c_str(), &sa.sin_addr); if (getnameinfo((struct sockaddr*)&sa, sizeof(sa), hostname, sizeof(hostname), nullptr, 0, 0) == 0) { return std::string(hostname); } return ip; // 解析失败则返回原IP } // 读取进程TCP连接信息 void get_process_network_info(const std::string& pid) { std::string path = "/proc/" + pid + "/net/tcp"; FILE* fp = fopen(path.c_str(), "r"); if (!fp) return; char line[512]; fgets(line, sizeof(line), fp); // 跳过表头行 while (fgets(line, sizeof(line), fp) != NULL) { std::istringstream iss(line); std::vector<std::string> fields; std::string field; while (iss >> field) fields.push_back(field); if (fields.size() < 4) continue; // 解析本地地址 size_t local_colon = fields[1].find(':'); std::string local_ip = hex_ip_to_decimal(fields[1].substr(0, local_colon)); uint16_t local_port = hex_port_to_decimal(fields[1].substr(local_colon + 1)); // 解析远程地址 size_t rem_colon = fields[2].find(':'); std::string rem_ip = hex_ip_to_decimal(fields[2].substr(0, rem_colon)); uint16_t rem_port = hex_port_to_decimal(fields[2].substr(rem_colon + 1)); // 获取远程主机名 std::string rem_hostname = ip_to_hostname(rem_ip); printf("本地: %s:%u | 远程: %s(%s):%u\n", local_ip.c_str(), local_port, rem_hostname.c_str(), rem_ip.c_str(), rem_port); } fclose(fp); }
注意事项:
- 读取其他用户进程的
/proc/[pid]/net目录需要对应权限(如root权限); - UDP为无连接协议,部分记录的远程地址可能为空;
- 编译时需链接网络库:
g++ 代码文件.cpp -o 可执行文件 -lresolv
内容的提问来源于stack exchange,提问作者urivskay
相关产品推荐
相关产品推荐

