Linux系统不维护用户累计在线时长,who和uptime仅显示当前会话时间,内核无相关API;last需root权限且解析复杂,可靠方案只能由应用层自行记录登录登出时间戳。
who 和 uptime 无法直接得到“当前用户累计在线时长”这是一个常见误解:很多开发者以为 who -u 或 uptime 能给出某个用户的总登录时间,但其实它们只反映当前会话的持续时间(比如 who -u 显示的是该 shell 登录以来的秒数),不是历史累计值。操作系统内核不维护单个用户的“累计在线时长”这一统计项,它不属于标准 POSIX 接口范畴。
Linux/Unix 没有提供类似 getlogin() 或 getpwuid() 那样能返回累计时间的系统调用或 libc 函数。Windows 同样没有 GetUserTotalUptime() 这类 API。这意味着你不能靠 sysconf()、clock_gettime() 或 GetTickCount64() 得到这个值——它们返回的是系统启动时间或进程运行时间,和用户无关。
last 命令输出的是登录记录(来自 /var/log/wtmp),但需 root 权限读取,且格式非结构化/var/log/wtmp,C++ 程序用 fopen("/var/log/wtmp", "r") 会失败并返回 NULL
wtmp 需要理解 struct utmp 布局,不同 glibc 版本字段偏移可能变化last 命令管道解析 + 时间计算如果你确实需要估算(注意:只是估算,非精确累计),可以 spawn last 并过滤当前用户名,再逐行提取登录/登出时间。前提是:last 可用、wtmp 未被轮转清空、用户有执行权限。
#include <cstdio>#include <string>#include <cstdlib>#include <ctime><p>// 示例:粗略计算最近 10 次登录的总时长(单位秒)std::time_t estimate_user_total_uptime(const std::string& username) {std::string cmd = "last -n 10 " + username + " 2>/dev/null | awk '$1=="" + username + "" && $9=="logged" {print $5,$6,$7,$8,$9,$10}'";FILE* fp = popen(cmd.c_str(), "r");if (!fp) return 0;</p><pre class='brush:php;toolbar:false;'>char line[256];std::time_t total = 0;while (fgets(line, sizeof(line), fp)) { // 实际需解析日期字符串为 time_t,此处省略转换逻辑 // 注意:last 输出格式依赖 locale,可能含 "reboot"、"still logged in" 等异常行}pclose(fp);return total;
}
立即学习“C++免费学习笔记(深入)”;
"still logged in" 这类状态,对应当前会话,结束时间应取 time(nullptr)
last 默认只查最近几周记录,wtmp 被 logrotate 清理后历史数据即丢失last 输出字段数不一致(如 Ubuntu 和 CentOS 的日期列位置不同)如果业务场景真需要准确累计值(比如计费系统),唯一健壮做法是在你的程序每次用户登录时写入时间戳,登出时更新时长,并持久化到数据库或本地文件。不要依赖系统日志。
/tmp 存储,应放在用户 home 目录下带权限控制的文件(如 $HOME/.app/uptime.log)系统本身不存这个数,硬从 wtmp 挖只是碰运气。想准,就得自己记。