C++获取当前登录用户累计在线时长应调用systemd-logind的D-Bus接口,而非who/uptime组合;需连接org.freedesktop.login1服务,调用ListSessions和GetSession获取active会话的Timestamp,再与当前时间相减求和。

Linux下用 who 和 uptime 组合估算登录时长不准确
直接调用 who 只能拿到当前终端登录时间(who -u 输出的空闲时间不是在线时长),而 uptime 返回的是系统启动时间,不是用户登录时间。两者相减会误把系统重启前的登录算进去,尤其对 systemd 管理的 session 更不可靠。
-
who的时间戳来自 utmp 记录,但部分桌面环境(如 GNOME Wayland)不写入 utmp,导致who查不到图形会话 - 同一用户多个终端登录时,
who会返回多行,需按LOGIN字段去重合并,不能简单取最早时间 - SSH 登录后断开连接但未退出 shell(如网络中断),
who仍显示该会话,实际已离线
C++ 调用 logind D-Bus 接口获取真实活跃会话时长
systemd-logind 是现代 Linux 桌面/服务器的会话权威来源,它维护每个用户 session 的精确生命周期(包括图形、TTY、SSH 会话),且支持查询 State 和 Timestamp。C++ 需通过 D-Bus 通信获取,而非解析文本命令输出。
- 连接地址固定为
unix:path=/run/dbus/system_bus_socket,无需依赖DBUS_SESSION_BUS_ADDRESS - 目标服务名是
org.freedesktop.login1,对象路径是/org/freedesktop/login1 - 调用
ListSessions方法返回所有 session 列表,再对每个 session 调用GetSession获取详细信息 - 关键字段:
State必须为active(非online或closing),Timestamp是毫秒级 Unix 时间戳,需转为秒再与time(nullptr)相减
示例片段(需链接 libdbus-1):
// 精简版逻辑示意,省略错误检查
DBusConnection *conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
DBusMessage *msg = dbus_message_new_method_call(
"org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
"ListSessions"
);
// ... 发送并解析响应,遍历 sessions 数组
// 对每个 session_path 调用 GetSession 获取 State/Timestamp
Windows 上必须用 NetUserGetInfo + WTSQuerySessionInformation 双查
Windows 没有统一“登录时长”概念:本地账户登录时间藏在 SAM 数据库(需管理员权限),而远程桌面/RDP 会话的活跃状态只能通过 Terminal Services API 查询。两者不能混用,且普通用户权限下多数字段不可读。
立即学习“C++免费学习笔记(深入)”;
-
NetUserGetInfo的level 1003返回usr1003_last_logon,但这是**上次成功认证时间**,不是当前会话开始时间 -
WTSQuerySessionInformation的WTSSessionInfoEx可查ConnectTime和DisconnectTime,但仅对 RDP/Console 会话有效,WinLogon 本地登录无此记录 - 当前登录用户需先用
WTSGetActiveConsoleSessionId()或ProcessIdToSessionId(GetCurrentProcessId(), &sid)获取 session ID,再查对应信息 - 若用户通过锁屏后恢复,
ConnectTime不更新,实际在线时长应从锁屏前持续计算——Windows 不暴露该状态,只能靠应用层自己记录
macOS 需解析 utmpx 并过滤 USER_PROCESS 类型
macOS 的 utmpx 文件(/var/run/utmpx)记录比 Linux 更严格,但默认不启用;需确认 launchd 已加载 com.apple.utmpx 服务。直接 fopen("/var/run/utmpx") 失败时,说明 utmpx 未激活或权限不足(需 root)。
- 遍历
setutxent()→getutxent(),跳过type != USER_PROCESS的条目(如RUN_LVL、BOOT_TIME) - 匹配当前用户名(
ut_user字段),取ut_tv.tv_sec作为登录时间戳 - 注意:图形会话(Aqua)由
loginwindow进程发起,其ut_user是真实用户名,但ut_host为空;SSH 会话则有ut_host值 - macOS 12+ 对 utmpx 写入更保守,某些 M1/M2 设备上图形登录可能不写入,此时需 fallback 到
ps aux | grep loginwindow的启动时间(不推荐,稳定性差)
跨平台方案不存在,每个系统都得单独适配;最易被忽略的是权限问题——Linux D-Bus 调用常因 polkit 规则拒绝,Windows 需 manifest 声明 requireAdministrator,macOS utmpx 读取需 root。
文章来自机圈观察员网,发布者:,转载请注明出处:https://www.jqgcy.com/xitongjiaocheng/123873.html