languages: English documentation
旨在为了简化开发人员需要获取系统信息时的搜索过程。本仓库提供了常见的信息如系统名称、网络适配器地址、磁盘容量的API小Demo,并叙述了写这些API时容易进入的误区。提供的Demo通常包括Windows平台(在Windows10上测试)和Linux平台(在kernel版本5+上测试)。能够获取的信息如下目录。欢迎各位系统软件开发者提出需求或补充Demo。
目录
显示结果:
computer name: DESKTOP-ABCD
computer full name: aa.bb.DESKTOP-ABCD
API文档:
GetComputerNameA function (winbase.h) - Win32 apps | Microsoft Docs
GetComputerNameExA function (sysinfoapi.h) - Win32 apps | Microsoft Docs
显示结果:
login user name: Alice
API文档:
GetUserNameA function (winbase.h) - Win32 apps | Microsoft Docs
显示结果:
OS version: Windows10
注意:
版本信息在VersionHelpers.h
里通过类似IsWindows10OrGreater()
和IsWindowsServer()
来获取,但是这个API目的是为了测试软件的兼容性而不是获取版本,Windows8及以上依赖于manifest list
,若没有此文件,此API只会得到系统版本是Windows8的结果。
***** For applications that have been manifested for Windows 8.1 or Windows 10. Applications not manifested for Windows 8.1 or Windows 10 will return the Windows 8 OS version value (6.2). To manifest your applications for Windows 8.1 or Windows 10, refer to Targeting your application for Windows.
因此如要得到更加详细的信息需要通过RtlGetVersion
动态获取。
Operating System Version - Win32 apps | Microsoft Docs
显示结果:
CPU utilization: 50.0
注意:
一种常规的思路是根据CPU运行的空闲时间和忙碌时间来算出使用率,在Linux上确实是这么算的。但是Windows上若要和任务管理器里显示的值对比,发现此计算的值会小一些。原因是“利用率”的定义问题,任务管理器中利用率实际上是结合了CPU当前频率算出来的,而不是简单的根据CPU时间计算。幸运的是我们不需要知道算法,在性能监视器里可以直接拿到这个值。
我们可以在性能监视器里看到,一个是Processor Time
,还有一个是Processor Utility
,Processor Time
是根据CPU运行的空闲时间和忙碌时间来算出来的,而Processor Utility
才是任务管理器里显示的数值。通过性能计数器,我们可以拿到此数值。
Using Performance Counters - Win32 apps | Microsoft Docs
显示结果:
memory total size: 7.8GB
memory used size: 5.8GB
API文档:
GlobalMemoryStatusEx function (sysinfoapi.h) - Win32 apps | Microsoft Docs
显示结果:
system now time: 2022-1-31-15-30
system has run: 10932s
API文档:
GlobalMemoryStatusEx function (sysinfoapi.h) - Win32 apps | Microsoft Docs
GetTickCount64 function (sysinfoapi.h) - Win32 apps | Microsoft Docs
显示结果:
IPv4 address: 192.168.1.30
MAC address: 1f:2d:3c:4d:5f:6e
status: OK
注意:
此API会返回一个链表,该链表会列出所有网络适配器包括虚拟网络适配器(如虚拟机、回环地址)的信息,包括IP地址和MAC地址,IP地址可能会有多个,应注意遍历全部。此外,IPv4和IPv6的传入FLAG不同,返回的是不同的链表。
GetAdaptersAddresses function (iphlpapi.h) - Win32 apps | Microsoft Docs
显示结果:
upload rate: 10.1KB/
download rate: 16.0KB/s
注意:
GetAdaptersAddresses
API返回的链表的节点中有Speed
字段,但此字段是指网卡的最大速率。要想获得传输速率需要读取电脑全部的物理接口,获得累积的流量信息,自行计算。此GetIfTable
API会返回所有物理接口,因此需要根据MAC地址筛选网卡的接口。
GetIfTable function (iphlpapi.h) - Win32 apps | Microsoft Docs
显示结果:
disk name: C:/, total space: 503.13GB, free space: 345.23GB
API文档:
GetLogicalDriveStringsW function (fileapi.h) - Win32 apps | Microsoft Docs
GetDiskFreeSpaceExA function (fileapi.h) - Win32 apps | Microsoft Docs
Linux系统不像Windows那样有便捷的、统一的API可以直接拿到数据,大多数也没有很完美的实现案例。这里列举出几种实现思路。
-
使用shell命令
shell命令嵌入到程序中执行,然后保存结果。这种方法的优点是很简单,系统的shell命令已经帮我们做了海量的处理。缺点是只能拿到字符数据,需要自己解析,另外使用这种方法实质上是在后台新建进程通过
bin/sh
运行命令然后拿到输出字符。这种方法涉及到进程的上下文切换开销较大,与直接调用具体功能的API有百倍速度差距。若不考虑性能问题,使用这种方法最为方便。具体API如下
-
读取
/proc
文件系统里的文件/proc
是一个在RAM里的临时的文件系统,保存着系统运行的信息。我们可以通过读取文件然后拿到数据,这种方法虽然也伴随着文件的读写,会产生IO中断,但是比方法1相比性能消耗会小一些。 -
使用用户API
这种方法类似于Windows获取信息的方法,利用系统提供的用户API获取到较为原始的信息。直接调用API性能消耗会比较小。
-
使用内核API
这种方法最接近底层,性能消耗最小,但是编程复杂度大幅度提升。
总的来说,从性能优秀程度上来看方法1<2<3<4,从获取信息的方便程度上1>2>3>4。本手册主要使用方法2和方法3,即读取/proc
文件系统和用户API。
显示结果:
computer name: Ubuntu
computer full name: Unbuntu.aa.bb
API文档:
uname(2) - Linux manual page (man7.org)
显示结果:
login user name: Alice
API文档:
getuid(2) - Linux manual page (man7.org)
getpwuid(3p) - Linux manual page (man7.org)
显示结果:
OS version: Ubuntu
注意:
这里获取到的是内核版本。
[uname(2) - Linux manual page (man7.org)](https://docs.microsoft.com/en-us/windows/win32/sysinfo/operating-system-version)
显示结果:
CPU utilization: 50.0
注意:
根据CPU运行的空闲时间和忙碌时间来算出使用率,这里需要从/proc
文件系统里读取CPU统计数据进行计算。
文件路径为:/proc/stat
显示结果:
memory total size: 7.8GB
memory used size: 7.8GB=
API文档:
sysinfo(2) - Linux manual page (man7.org)
显示结果:
system now time: 2022-1-31-15-30
system has run: 10932s
API文档:
time(2) - Linux manual page (man7.org)
gmtime(3p) - Linux manual page (man7.org)
sysinfo(2) - Linux manual page (man7.org)
显示结果:
NIC name: eth0
status: OK
IPv4 address: 192.168.1.30
IPv6 address: 2001:db8:85a3:8d3:1319:8a2e:370:7348
upload rate: 10.1KB/s
download rate: 16.0KB/s
注意:
此API会返回一个链表,该链表会列出所有网络适配器包括虚拟网络适配器(如虚拟机、回环地址)的信息,包括名称、IPv4地址、IPv6地址、传输字节数。但是这里每个网卡的每一项都是单独的一个链表节点,同一个网卡的链表节点具有相同的名字,但根据FLAG的不同而存储不同项。因此需要遍历全部才能收集齐一个网卡的信息。
getifaddrs(3) - Linux manual page (man7.org)
显示结果:
MAC address: 1f:2d:3c:4d:5f:6e
注意:
使用ioctl
来获取接口的硬件地址,需要实现创建socket,通过该socket和网卡名称来获取MAC地址。
ioctl(2) - Linux manual page (man7.org)
显示结果:
disk name: dev/sda2, mount path: /, total space: 503.13GB, free space: 345.23GB
注意:
本结果通过读取/proc/mounts拿到所有磁盘的名称和挂载路径,再通过statfs
查询挂载路径的空间。