C++如何获取操作系统的当前登录用户累计实时在线时长统计

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

c++如何获取操作系统的当前登录用户累计实时在线时长统计

Linux下用 whouptime 组合估算登录时长不准确

直接调用 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 会话),且支持查询 StateTimestamp。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(非 onlineclosing),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++免费学习笔记(深入)”;

  • NetUserGetInfolevel 1003 返回 usr1003_last_logon,但这是**上次成功认证时间**,不是当前会话开始时间
  • WTSQuerySessionInformationWTSSessionInfoEx 可查 ConnectTimeDisconnectTime,但仅对 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_LVLBOOT_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

如何在 Golang 中把 JSON 字符串流式反序列化为动态的数组切片
上一篇 2026-07-01 14:13
HTML全局属性is对传统库jQuery插件化改造的平滑过渡指南
下一篇 2026-07-01 14:13

相关推荐