一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

C++怎样获取操作系统的当前用户累计在线时长

时间:2026-06-23 08:30:46 编辑:袖梨 来源:一聚教程网

Linux系统不维护用户累计在线时长,who和uptime仅显示当前会话时间,内核无相关API;last需root权限且解析复杂,可靠方案只能由应用层自行记录登录登出时间戳。

Linux下用 whouptime 无法直接得到“当前用户累计在线时长”

这是一个常见误解:很多开发者以为 who -uuptime 能给出某个用户的总登录时间,但其实它们只反映当前会话的持续时间(比如 who -u 显示的是该 shell 登录以来的秒数),不是历史累计值。操作系统内核不维护单个用户的“累计在线时长”这一统计项,它不属于标准 POSIX 接口范畴。

C++ 程序无法直接调用系统 API 获取累计在线时长

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 挖只是碰运气。想准,就得自己记。

热门栏目