ComputerUtil.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  1. // Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
  2. //
  3. // 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
  4. //
  5. // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
  6. namespace Admin.NET.Core;
  7. public static class ComputerUtil
  8. {
  9. /// <summary>
  10. /// 内存信息
  11. /// </summary>
  12. /// <returns></returns>
  13. public static MemoryMetrics GetComputerInfo()
  14. {
  15. MemoryMetrics memoryMetrics;
  16. if (IsMacOS())
  17. {
  18. memoryMetrics = MemoryMetricsClient.GetMacOSMetrics();
  19. }
  20. else if (IsUnix())
  21. {
  22. memoryMetrics = MemoryMetricsClient.GetUnixMetrics();
  23. }
  24. else
  25. {
  26. memoryMetrics = MemoryMetricsClient.GetWindowsMetrics();
  27. }
  28. memoryMetrics.FreeRam = Math.Round(memoryMetrics.Free / 1024, 2) + "GB";
  29. memoryMetrics.UsedRam = Math.Round(memoryMetrics.Used / 1024, 2) + "GB";
  30. memoryMetrics.TotalRam = Math.Round(memoryMetrics.Total / 1024, 2) + "GB";
  31. memoryMetrics.RamRate = Math.Ceiling(100 * memoryMetrics.Used / memoryMetrics.Total) + "%";
  32. var cpuRates = GetCPURates();
  33. if (cpuRates != null)
  34. {
  35. memoryMetrics.CpuRates = cpuRates.Select(u => Math.Ceiling(u.ParseToDouble()) + "%").ToList();
  36. }
  37. memoryMetrics.CpuRate = memoryMetrics.CpuRates[0];
  38. return memoryMetrics;
  39. }
  40. /// <summary>
  41. /// 获取正确的操作系统版本(Linux获取发行版本)
  42. /// </summary>
  43. /// <returns></returns>
  44. public static String GetOSInfo()
  45. {
  46. string operation = string.Empty;
  47. if (IsMacOS())
  48. {
  49. var output = ShellUtil.Bash("sw_vers | awk 'NR<=2{printf \"%s \", $NF}'");
  50. if (output != null)
  51. {
  52. operation = output.Replace("%", string.Empty);
  53. }
  54. }
  55. else if (IsUnix())
  56. {
  57. var output = ShellUtil.Bash("awk -F= '/^VERSION_ID/ {print $2}' /etc/os-release | tr -d '\"'");
  58. operation = output ?? string.Empty;
  59. }
  60. else
  61. {
  62. operation = RuntimeInformation.OSDescription;
  63. }
  64. return operation;
  65. }
  66. /// <summary>
  67. /// 磁盘信息
  68. /// </summary>
  69. /// <returns></returns>
  70. public static List<DiskInfo> GetDiskInfos()
  71. {
  72. var diskInfos = new List<DiskInfo>();
  73. if (IsMacOS())
  74. {
  75. var output = ShellUtil.Bash(@"df -m | awk '/^\/dev\/disk/ {print $1,$2,$3,$4,$5}'");
  76. var disks = output.Split('\n', StringSplitOptions.RemoveEmptyEntries);
  77. if (disks.Length < 1) return diskInfos;
  78. foreach (var item in disks)
  79. {
  80. var disk = item.Split(' ', (char)StringSplitOptions.RemoveEmptyEntries);
  81. if (disk.Length < 5) continue;
  82. var diskInfo = new DiskInfo()
  83. {
  84. DiskName = disk[0],
  85. TypeName = ShellUtil.Bash("diskutil info " + disk[0] + " | awk '/File System Personality/ {print $4}'").Replace("\n", string.Empty),
  86. TotalSize = Math.Round(long.Parse(disk[1]) / 1024.0m, 2, MidpointRounding.AwayFromZero),
  87. Used = Math.Round(long.Parse(disk[2]) / 1024.0m, 2, MidpointRounding.AwayFromZero),
  88. AvailableFreeSpace = Math.Round(long.Parse(disk[3]) / 1024.0m, 2, MidpointRounding.AwayFromZero),
  89. AvailablePercent = decimal.Parse(disk[4].Replace("%", ""))
  90. };
  91. diskInfos.Add(diskInfo);
  92. }
  93. }
  94. else if (IsUnix())
  95. {
  96. var output = ShellUtil.Bash(@"df -mT | awk '/^\/dev\/(sd|vd|xvd|nvme|sda|vda|mapper)/ {print $1,$2,$3,$4,$5,$6}'");
  97. var disks = output.Split('\n', StringSplitOptions.RemoveEmptyEntries);
  98. if (disks.Length < 1) return diskInfos;
  99. //var rootDisk = disks[1].Split(' ', (char)StringSplitOptions.RemoveEmptyEntries);
  100. //if (rootDisk == null || rootDisk.Length < 1)
  101. // return diskInfos;
  102. foreach (var item in disks)
  103. {
  104. var disk = item.Split(' ', (char)StringSplitOptions.RemoveEmptyEntries);
  105. if (disk.Length < 6) continue;
  106. var diskInfo = new DiskInfo()
  107. {
  108. DiskName = disk[0],
  109. TypeName = disk[1],
  110. TotalSize = Math.Round(long.Parse(disk[2]) / 1024.0m, 2, MidpointRounding.AwayFromZero),
  111. Used = Math.Round(long.Parse(disk[3]) / 1024.0m, 2, MidpointRounding.AwayFromZero),
  112. AvailableFreeSpace = Math.Round(long.Parse(disk[4]) / 1024.0m, 2, MidpointRounding.AwayFromZero),
  113. AvailablePercent = decimal.Parse(disk[5].Replace("%", ""))
  114. };
  115. diskInfos.Add(diskInfo);
  116. }
  117. }
  118. else
  119. {
  120. var driveList = DriveInfo.GetDrives().Where(u => u.IsReady);
  121. foreach (var item in driveList)
  122. {
  123. if (item.DriveType == DriveType.CDRom) continue;
  124. var diskInfo = new DiskInfo()
  125. {
  126. DiskName = item.Name,
  127. TypeName = item.DriveType.ToString(),
  128. TotalSize = Math.Round(item.TotalSize / 1024 / 1024 / 1024.0m, 2, MidpointRounding.AwayFromZero),
  129. AvailableFreeSpace = Math.Round(item.AvailableFreeSpace / 1024 / 1024 / 1024.0m, 2, MidpointRounding.AwayFromZero),
  130. };
  131. diskInfo.Used = diskInfo.TotalSize - diskInfo.AvailableFreeSpace;
  132. diskInfo.AvailablePercent = decimal.Ceiling(diskInfo.Used / (decimal)diskInfo.TotalSize * 100);
  133. diskInfos.Add(diskInfo);
  134. }
  135. }
  136. return diskInfos;
  137. }
  138. /// <summary>
  139. /// 获取外网IP地址
  140. /// </summary>
  141. /// <returns></returns>
  142. public static string GetIpFromOnline()
  143. {
  144. try
  145. {
  146. var url = "https://www.ip.cn/api/index?ip&type=0";
  147. var httpRemoteService = App.GetRequiredService<IHttpRemoteService>();
  148. var str = httpRemoteService.GetAsStringAsync(url).GetAwaiter().GetResult();
  149. var resp = JSON.Deserialize<IpCnResp>(str);
  150. return resp.Ip + " " + resp.Address;
  151. }
  152. catch
  153. {
  154. return "unknow";
  155. }
  156. }
  157. public static bool IsUnix()
  158. {
  159. return RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
  160. }
  161. public static bool IsMacOS()
  162. {
  163. return RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
  164. }
  165. public static List<string> GetCPURates()
  166. {
  167. var cpuRates = new List<string>();
  168. string output = "";
  169. if (IsMacOS())
  170. {
  171. output = ShellUtil.Bash("top -l 1 | grep \"CPU usage\" | awk '{print $3 + $5}'");
  172. cpuRates.Add(output.Trim());
  173. }
  174. else if (IsUnix())
  175. {
  176. output = ShellUtil.Bash("awk '{u=$2+$4; t=$2+$4+$5; if (NR==1){u1=u; t1=t;} else print ($2+$4-u1) * 100 / (t-t1); }' <(grep 'cpu ' /proc/stat) <(sleep 1;grep 'cpu ' /proc/stat)");
  177. cpuRates.Add(output.Trim());
  178. }
  179. else
  180. {
  181. try
  182. {
  183. output = ShellUtil.Cmd("wmic", "cpu get LoadPercentage");
  184. }
  185. catch (Exception)
  186. {
  187. output = ShellUtil.PowerShell("Get-CimInstance -ClassName Win32_Processor | Select-Object LoadPercentage");
  188. output = output.Replace("@", string.Empty).Replace("{", string.Empty).Replace("}", string.Empty).Replace("=", string.Empty).Trim();
  189. }
  190. cpuRates.AddRange(output.Replace("LoadPercentage", string.Empty).Trim().Split("\r\r\n"));
  191. }
  192. return cpuRates;
  193. }
  194. /// <summary>
  195. /// 获取系统运行时间
  196. /// </summary>
  197. /// <returns></returns>
  198. public static string GetRunTime()
  199. {
  200. string runTime = string.Empty;
  201. string output = "";
  202. if (IsMacOS())
  203. {
  204. // macOS 获取系统启动时间:
  205. // sysctl -n kern.boottime | awk '{print $4}' | tr -d ','
  206. // 返回:1705379131
  207. // 使用date格式化即可
  208. output = ShellUtil.Bash("date -r $(sysctl -n kern.boottime | awk '{print $4}' | tr -d ',') +\"%Y-%m-%d %H:%M:%S\"").Trim();
  209. runTime = DateTimeUtil.FormatTime((DateTime.Now - output.ParseToDateTime()).TotalMilliseconds.ToString().Split('.')[0].ParseToLong());
  210. }
  211. else if (IsUnix())
  212. {
  213. output = ShellUtil.Bash("date -d \"$(awk -F. '{print $1}' /proc/uptime) second ago\" +\"%Y-%m-%d %H:%M:%S\"").Trim();
  214. runTime = DateTimeUtil.FormatTime((DateTime.Now - output.ParseToDateTime()).TotalMilliseconds.ToString().Split('.')[0].ParseToLong());
  215. }
  216. else
  217. {
  218. try
  219. {
  220. output = ShellUtil.Cmd("wmic", "OS get LastBootUpTime/Value");
  221. string[] outputArr = output.Split('=', (char)StringSplitOptions.RemoveEmptyEntries);
  222. if (outputArr.Length == 2)
  223. runTime = DateTimeUtil.FormatTime((DateTime.Now - outputArr[1].Split('.')[0].ParseToDateTime()).TotalMilliseconds.ToString().Split('.')[0].ParseToLong());
  224. }
  225. catch (Exception)
  226. {
  227. output = ShellUtil.PowerShell("Get-CimInstance -ClassName Win32_OperatingSystem | Select-Object LastBootUpTime");
  228. output = output.Replace("LastBootUpTime", string.Empty).Replace("@", string.Empty).Replace("{", string.Empty).Replace("}", string.Empty).Replace("=", string.Empty).Trim();
  229. runTime = DateTimeUtil.FormatTime((DateTime.Now - output.ParseToDateTime()).TotalMilliseconds.ToString().Split('.')[0].ParseToLong());
  230. }
  231. }
  232. return runTime;
  233. }
  234. }
  235. /// <summary>
  236. /// IP信息
  237. /// </summary>
  238. public class IpCnResp
  239. {
  240. public string Ip { get; set; }
  241. public string Address { get; set; }
  242. }
  243. /// <summary>
  244. /// 内存信息
  245. /// </summary>
  246. public class MemoryMetrics
  247. {
  248. [Newtonsoft.Json.JsonIgnore]
  249. [System.Text.Json.Serialization.JsonIgnore]
  250. public double Total { get; set; }
  251. [Newtonsoft.Json.JsonIgnore]
  252. [System.Text.Json.Serialization.JsonIgnore]
  253. public double Used { get; set; }
  254. [Newtonsoft.Json.JsonIgnore]
  255. [System.Text.Json.Serialization.JsonIgnore]
  256. public double Free { get; set; }
  257. /// <summary>
  258. /// 已用内存
  259. /// </summary>
  260. public string UsedRam { get; set; }
  261. /// <summary>
  262. /// CPU使用率%
  263. /// </summary>
  264. public List<string> CpuRates { get; set; }
  265. public string CpuRate { get; set; }
  266. /// <summary>
  267. /// 总内存 GB
  268. /// </summary>
  269. public string TotalRam { get; set; }
  270. /// <summary>
  271. /// 内存使用率 %
  272. /// </summary>
  273. public string RamRate { get; set; }
  274. /// <summary>
  275. /// 空闲内存
  276. /// </summary>
  277. public string FreeRam { get; set; }
  278. }
  279. /// <summary>
  280. /// 磁盘信息
  281. /// </summary>
  282. public class DiskInfo
  283. {
  284. /// <summary>
  285. /// 磁盘名
  286. /// </summary>
  287. public string DiskName { get; set; }
  288. /// <summary>
  289. /// 类型名
  290. /// </summary>
  291. public string TypeName { get; set; }
  292. /// <summary>
  293. /// 总剩余
  294. /// </summary>
  295. public decimal TotalFree { get; set; }
  296. /// <summary>
  297. /// 总量
  298. /// </summary>
  299. public decimal TotalSize { get; set; }
  300. /// <summary>
  301. /// 已使用
  302. /// </summary>
  303. public decimal Used { get; set; }
  304. /// <summary>
  305. /// 可使用
  306. /// </summary>
  307. public decimal AvailableFreeSpace { get; set; }
  308. /// <summary>
  309. /// 使用百分比
  310. /// </summary>
  311. public decimal AvailablePercent { get; set; }
  312. }
  313. public class MemoryMetricsClient
  314. {
  315. /// <summary>
  316. /// windows系统获取内存信息
  317. /// </summary>
  318. /// <returns></returns>
  319. public static MemoryMetrics GetWindowsMetrics()
  320. {
  321. string output = "";
  322. var metrics = new MemoryMetrics();
  323. try
  324. {
  325. output = ShellUtil.Cmd("wmic", "OS get FreePhysicalMemory,TotalVisibleMemorySize /Value");
  326. var lines = output.Trim().Split('\n', (char)StringSplitOptions.RemoveEmptyEntries);
  327. if (lines.Length <= 1) return metrics;
  328. var freeMemoryParts = lines[0].Split('=', (char)StringSplitOptions.RemoveEmptyEntries);
  329. var totalMemoryParts = lines[1].Split('=', (char)StringSplitOptions.RemoveEmptyEntries);
  330. metrics.Total = Math.Round(double.Parse(totalMemoryParts[1]) / 1024, 0);
  331. metrics.Free = Math.Round(double.Parse(freeMemoryParts[1]) / 1024, 0);//m
  332. }
  333. catch (Exception)
  334. {
  335. output = ShellUtil.PowerShell("Get-CimInstance -ClassName Win32_OperatingSystem | Select-Object FreePhysicalMemory, TotalVisibleMemorySize");
  336. output = output.Replace("@", string.Empty).Replace("{", string.Empty).Replace("}", string.Empty).Trim();
  337. var lines = output.Trim().Split(';', (char)StringSplitOptions.RemoveEmptyEntries);
  338. // 跳过表头与分隔线(通常为前两行)
  339. if (lines.Length >= 2)
  340. {
  341. // 解析并转换为MB(原单位为KB)
  342. metrics.Free = Math.Round(double.Parse(lines[0].Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries)[1]) / 1024, 0);
  343. metrics.Total = Math.Round(double.Parse(lines[1].Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries)[1]) / 1024, 0);
  344. }
  345. }
  346. metrics.Used = metrics.Total - metrics.Free;
  347. return metrics;
  348. }
  349. /// <summary>
  350. /// Unix系统获取
  351. /// </summary>
  352. /// <returns></returns>
  353. public static MemoryMetrics GetUnixMetrics()
  354. {
  355. string output = ShellUtil.Bash("awk '/MemTotal/ {total=$2} /MemAvailable/ {available=$2} END {print total,available}' /proc/meminfo");
  356. var metrics = new MemoryMetrics();
  357. var memory = output.Split(' ', (char)StringSplitOptions.RemoveEmptyEntries);
  358. if (memory.Length != 2) return metrics;
  359. metrics.Total = double.Parse(memory[0]) / 1024;
  360. metrics.Free = double.Parse(memory[1]) / 1024;
  361. metrics.Used = metrics.Total - metrics.Free;
  362. return metrics;
  363. }
  364. /// <summary>
  365. /// macOS系统获取
  366. /// </summary>
  367. /// <returns></returns>
  368. public static MemoryMetrics GetMacOSMetrics()
  369. {
  370. var metrics = new MemoryMetrics();
  371. //物理内存大小
  372. var total = ShellUtil.Bash("sysctl -n hw.memsize | awk '{printf \"%.2f\", $1/1024/1024}'");
  373. metrics.Total = float.Parse(total.Replace("%", string.Empty));
  374. //TODO:占用内存,检查效率
  375. var free = ShellUtil.Bash("top -l 1 -s 0 | awk '/PhysMem/ {print $6+$8}'");
  376. metrics.Free = float.Parse(free);
  377. metrics.Used = metrics.Total - metrics.Free;
  378. return metrics;
  379. }
  380. }
  381. public class ShellUtil
  382. {
  383. /// <summary>
  384. /// linux 系统命令
  385. /// </summary>
  386. /// <param name="command"></param>
  387. /// <returns></returns>
  388. public static string Bash(string command)
  389. {
  390. var escapedArgs = command.Replace("\"", "\\\"");
  391. var process = new Process()
  392. {
  393. StartInfo = new ProcessStartInfo
  394. {
  395. FileName = "/bin/bash",
  396. Arguments = $"-c \"{escapedArgs}\"",
  397. RedirectStandardOutput = true,
  398. UseShellExecute = false,
  399. CreateNoWindow = true,
  400. }
  401. };
  402. process.Start();
  403. string result = process.StandardOutput.ReadToEnd();
  404. process.WaitForExit();
  405. process.Dispose();
  406. return result;
  407. }
  408. /// <summary>
  409. /// windows CMD 系统命令
  410. /// </summary>
  411. /// <param name="fileName"></param>
  412. /// <param name="args"></param>
  413. /// <returns></returns>
  414. public static string Cmd(string fileName, string args)
  415. {
  416. var info = new ProcessStartInfo
  417. {
  418. FileName = fileName,
  419. Arguments = args,
  420. RedirectStandardOutput = true
  421. };
  422. var output = string.Empty;
  423. using (var process = Process.Start(info))
  424. {
  425. output = process.StandardOutput.ReadToEnd();
  426. }
  427. return output;
  428. }
  429. /// <summary>
  430. /// Windows POWERSHELL 系统命令
  431. /// </summary>
  432. /// <param name="script"></param>
  433. /// <returns></returns>
  434. public static string PowerShell(string script)
  435. {
  436. using var PowerShellInstance = System.Management.Automation.PowerShell.Create();
  437. PowerShellInstance.AddScript(script);
  438. var PSOutput = PowerShellInstance.Invoke();
  439. var output = new StringBuilder();
  440. foreach (var outputItem in PSOutput)
  441. {
  442. output.AppendLine(outputItem.ToString());
  443. }
  444. return output.ToString();
  445. }
  446. }
  447. public class ShellHelper
  448. {
  449. /// <summary>
  450. /// Linux 系统命令
  451. /// </summary>
  452. /// <param name="command"></param>
  453. /// <returns></returns>
  454. public static string Bash(string command)
  455. {
  456. var escapedArgs = command.Replace("\"", "\\\"");
  457. var process = new Process()
  458. {
  459. StartInfo = new ProcessStartInfo
  460. {
  461. FileName = "/bin/bash",
  462. Arguments = $"-c \"{escapedArgs}\"",
  463. RedirectStandardOutput = true,
  464. UseShellExecute = false,
  465. CreateNoWindow = true,
  466. }
  467. };
  468. process.Start();
  469. string result = process.StandardOutput.ReadToEnd();
  470. process.WaitForExit();
  471. process.Dispose();
  472. return result;
  473. }
  474. /// <summary>
  475. /// Windows CMD 系统命令
  476. /// </summary>
  477. /// <param name="fileName"></param>
  478. /// <param name="args"></param>
  479. /// <returns></returns>
  480. public static string Cmd(string fileName, string args)
  481. {
  482. var info = new ProcessStartInfo
  483. {
  484. FileName = fileName,
  485. Arguments = args,
  486. RedirectStandardOutput = true
  487. };
  488. var output = string.Empty;
  489. using (var process = Process.Start(info))
  490. {
  491. output = process.StandardOutput.ReadToEnd();
  492. }
  493. return output;
  494. }
  495. /// <summary>
  496. /// Windows POWERSHELL 系统命令
  497. /// </summary>
  498. /// <param name="script"></param>
  499. /// <returns></returns>
  500. public static string PowerShell(string script)
  501. {
  502. using var PowerShellInstance = System.Management.Automation.PowerShell.Create();
  503. PowerShellInstance.AddScript(script);
  504. var PSOutput = PowerShellInstance.Invoke();
  505. var output = new StringBuilder();
  506. foreach (var outputItem in PSOutput)
  507. {
  508. output.AppendLine(outputItem.BaseObject.ToString());
  509. }
  510. return output.ToString();
  511. }
  512. }