ComputerUtil.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  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. return memoryMetrics;
  38. }
  39. /// <summary>
  40. /// 获取正确的操作系统版本(Linux获取发行版本)
  41. /// </summary>
  42. /// <returns></returns>
  43. public static String GetOSInfo()
  44. {
  45. string operation = string.Empty;
  46. if (IsMacOS())
  47. {
  48. var output = ShellUtil.Bash("sw_vers | awk 'NR<=2{printf \"%s \", $NF}'");
  49. if (output != null)
  50. {
  51. operation = output.Replace("%", string.Empty);
  52. }
  53. }
  54. else if (IsUnix())
  55. {
  56. var output = ShellUtil.Bash("awk -F= '/^VERSION_ID/ {print $2}' /etc/os-release | tr -d '\"'");
  57. operation = output ?? string.Empty;
  58. }
  59. else
  60. {
  61. operation = RuntimeInformation.OSDescription;
  62. }
  63. return operation;
  64. }
  65. /// <summary>
  66. /// 磁盘信息
  67. /// </summary>
  68. /// <returns></returns>
  69. public static List<DiskInfo> GetDiskInfos()
  70. {
  71. var diskInfos = new List<DiskInfo>();
  72. if (IsMacOS())
  73. {
  74. var output = ShellUtil.Bash(@"df -m | awk '/^\/dev\/disk/ {print $1,$2,$3,$4,$5}'");
  75. var disks = output.Split('\n', StringSplitOptions.RemoveEmptyEntries);
  76. if (disks.Length < 1) return diskInfos;
  77. foreach (var item in disks)
  78. {
  79. var disk = item.Split(' ', (char)StringSplitOptions.RemoveEmptyEntries);
  80. if (disk.Length < 5) continue;
  81. var diskInfo = new DiskInfo()
  82. {
  83. DiskName = disk[0],
  84. TypeName = ShellUtil.Bash("diskutil info " + disk[0] + " | awk '/File System Personality/ {print $4}'").Replace("\n", string.Empty),
  85. TotalSize = Math.Round(long.Parse(disk[1]) / 1024.0m, 2, MidpointRounding.AwayFromZero),
  86. Used = Math.Round(long.Parse(disk[2]) / 1024.0m, 2, MidpointRounding.AwayFromZero),
  87. AvailableFreeSpace = Math.Round(long.Parse(disk[3]) / 1024.0m, 2, MidpointRounding.AwayFromZero),
  88. AvailablePercent = decimal.Parse(disk[4].Replace("%", ""))
  89. };
  90. diskInfos.Add(diskInfo);
  91. }
  92. }
  93. else if (IsUnix())
  94. {
  95. var output = ShellUtil.Bash(@"df -mT | awk '/^\/dev\/(sd|vd|xvd|nvme|sda|vda|mapper)/ {print $1,$2,$3,$4,$5,$6}'");
  96. var disks = output.Split('\n', StringSplitOptions.RemoveEmptyEntries);
  97. if (disks.Length < 1) return diskInfos;
  98. //var rootDisk = disks[1].Split(' ', (char)StringSplitOptions.RemoveEmptyEntries);
  99. //if (rootDisk == null || rootDisk.Length < 1)
  100. // return diskInfos;
  101. foreach (var item in disks)
  102. {
  103. var disk = item.Split(' ', (char)StringSplitOptions.RemoveEmptyEntries);
  104. if (disk.Length < 6) continue;
  105. var diskInfo = new DiskInfo()
  106. {
  107. DiskName = disk[0],
  108. TypeName = disk[1],
  109. TotalSize = Math.Round(long.Parse(disk[2]) / 1024.0m, 2, MidpointRounding.AwayFromZero),
  110. Used = Math.Round(long.Parse(disk[3]) / 1024.0m, 2, MidpointRounding.AwayFromZero),
  111. AvailableFreeSpace = Math.Round(long.Parse(disk[4]) / 1024.0m, 2, MidpointRounding.AwayFromZero),
  112. AvailablePercent = decimal.Parse(disk[5].Replace("%", ""))
  113. };
  114. diskInfos.Add(diskInfo);
  115. }
  116. }
  117. else
  118. {
  119. var driveList = DriveInfo.GetDrives().Where(u => u.IsReady);
  120. foreach (var item in driveList)
  121. {
  122. if (item.DriveType == DriveType.CDRom) continue;
  123. var diskInfo = new DiskInfo()
  124. {
  125. DiskName = item.Name,
  126. TypeName = item.DriveType.ToString(),
  127. TotalSize = Math.Round(item.TotalSize / 1024 / 1024 / 1024.0m, 2, MidpointRounding.AwayFromZero),
  128. AvailableFreeSpace = Math.Round(item.AvailableFreeSpace / 1024 / 1024 / 1024.0m, 2, MidpointRounding.AwayFromZero),
  129. };
  130. diskInfo.Used = diskInfo.TotalSize - diskInfo.AvailableFreeSpace;
  131. diskInfo.AvailablePercent = decimal.Ceiling(diskInfo.Used / (decimal)diskInfo.TotalSize * 100);
  132. diskInfos.Add(diskInfo);
  133. }
  134. }
  135. return diskInfos;
  136. }
  137. /// <summary>
  138. /// 获取外网IP地址
  139. /// </summary>
  140. /// <returns></returns>
  141. public static string GetIpFromOnline()
  142. {
  143. try
  144. {
  145. var url = "https://www.ip.cn/api/index?ip&type=0";
  146. var httpRemoteService = App.GetRequiredService<IHttpRemoteService>();
  147. var str = httpRemoteService.GetAsStringAsync(url).GetAwaiter().GetResult();
  148. var resp = JSON.Deserialize<IpCnResp>(str);
  149. return resp.Ip + " " + resp.Address;
  150. }
  151. catch
  152. {
  153. return "unknow";
  154. }
  155. }
  156. public static bool IsUnix()
  157. {
  158. return RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
  159. }
  160. public static bool IsMacOS()
  161. {
  162. return RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
  163. }
  164. public static List<string> GetCPURates()
  165. {
  166. var cpuRates = new List<string>();
  167. if (IsMacOS())
  168. {
  169. string output = ShellUtil.Bash("top -l 1 | grep \"CPU usage\" | awk '{print $3 + $5}'");
  170. cpuRates.Add(output.Trim());
  171. }
  172. else if (IsUnix())
  173. {
  174. string 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)");
  175. cpuRates.Add(output.Trim());
  176. }
  177. else
  178. {
  179. string output = ShellUtil.Cmd("wmic", "cpu get LoadPercentage");
  180. cpuRates.AddRange(output.Replace("LoadPercentage", string.Empty).Trim().Split("\r\r\n"));
  181. }
  182. return cpuRates;
  183. }
  184. /// <summary>
  185. /// 获取系统运行时间
  186. /// </summary>
  187. /// <returns></returns>
  188. public static string GetRunTime()
  189. {
  190. string runTime = string.Empty;
  191. if (IsMacOS())
  192. {
  193. // macOS 获取系统启动时间:
  194. // sysctl -n kern.boottime | awk '{print $4}' | tr -d ','
  195. // 返回:1705379131
  196. // 使用date格式化即可
  197. string output = ShellUtil.Bash("date -r $(sysctl -n kern.boottime | awk '{print $4}' | tr -d ',') +\"%Y-%m-%d %H:%M:%S\"").Trim();
  198. runTime = DateTimeUtil.FormatTime((DateTime.Now - output.ParseToDateTime()).TotalMilliseconds.ToString().Split('.')[0].ParseToLong());
  199. }
  200. else if (IsUnix())
  201. {
  202. string output = ShellUtil.Bash("date -d \"$(awk -F. '{print $1}' /proc/uptime) second ago\" +\"%Y-%m-%d %H:%M:%S\"").Trim();
  203. runTime = DateTimeUtil.FormatTime((DateTime.Now - output.ParseToDateTime()).TotalMilliseconds.ToString().Split('.')[0].ParseToLong());
  204. }
  205. else
  206. {
  207. string output = ShellUtil.Cmd("wmic", "OS get LastBootUpTime/Value");
  208. string[] outputArr = output.Split('=', (char)StringSplitOptions.RemoveEmptyEntries);
  209. if (outputArr.Length == 2)
  210. runTime = DateTimeUtil.FormatTime((DateTime.Now - outputArr[1].Split('.')[0].ParseToDateTime()).TotalMilliseconds.ToString().Split('.')[0].ParseToLong());
  211. }
  212. return runTime;
  213. }
  214. }
  215. /// <summary>
  216. /// IP信息
  217. /// </summary>
  218. public class IpCnResp
  219. {
  220. public string Ip { get; set; }
  221. public string Address { get; set; }
  222. }
  223. /// <summary>
  224. /// 内存信息
  225. /// </summary>
  226. public class MemoryMetrics
  227. {
  228. [Newtonsoft.Json.JsonIgnore]
  229. [System.Text.Json.Serialization.JsonIgnore]
  230. public double Total { get; set; }
  231. [Newtonsoft.Json.JsonIgnore]
  232. [System.Text.Json.Serialization.JsonIgnore]
  233. public double Used { get; set; }
  234. [Newtonsoft.Json.JsonIgnore]
  235. [System.Text.Json.Serialization.JsonIgnore]
  236. public double Free { get; set; }
  237. /// <summary>
  238. /// 已用内存
  239. /// </summary>
  240. public string UsedRam { get; set; }
  241. /// <summary>
  242. /// CPU使用率%
  243. /// </summary>
  244. public List<string> CpuRates { get; set; }
  245. /// <summary>
  246. /// 总内存 GB
  247. /// </summary>
  248. public string TotalRam { get; set; }
  249. /// <summary>
  250. /// 内存使用率 %
  251. /// </summary>
  252. public string RamRate { get; set; }
  253. /// <summary>
  254. /// 空闲内存
  255. /// </summary>
  256. public string FreeRam { get; set; }
  257. }
  258. /// <summary>
  259. /// 磁盘信息
  260. /// </summary>
  261. public class DiskInfo
  262. {
  263. /// <summary>
  264. /// 磁盘名
  265. /// </summary>
  266. public string DiskName { get; set; }
  267. /// <summary>
  268. /// 类型名
  269. /// </summary>
  270. public string TypeName { get; set; }
  271. /// <summary>
  272. /// 总剩余
  273. /// </summary>
  274. public decimal TotalFree { get; set; }
  275. /// <summary>
  276. /// 总量
  277. /// </summary>
  278. public decimal TotalSize { get; set; }
  279. /// <summary>
  280. /// 已使用
  281. /// </summary>
  282. public decimal Used { get; set; }
  283. /// <summary>
  284. /// 可使用
  285. /// </summary>
  286. public decimal AvailableFreeSpace { get; set; }
  287. /// <summary>
  288. /// 使用百分比
  289. /// </summary>
  290. public decimal AvailablePercent { get; set; }
  291. }
  292. public class MemoryMetricsClient
  293. {
  294. /// <summary>
  295. /// windows系统获取内存信息
  296. /// </summary>
  297. /// <returns></returns>
  298. public static MemoryMetrics GetWindowsMetrics()
  299. {
  300. string output = ShellUtil.Cmd("wmic", "OS get FreePhysicalMemory,TotalVisibleMemorySize /Value");
  301. var metrics = new MemoryMetrics();
  302. var lines = output.Trim().Split('\n', (char)StringSplitOptions.RemoveEmptyEntries);
  303. if (lines.Length <= 1) return metrics;
  304. var freeMemoryParts = lines[0].Split('=', (char)StringSplitOptions.RemoveEmptyEntries);
  305. var totalMemoryParts = lines[1].Split('=', (char)StringSplitOptions.RemoveEmptyEntries);
  306. metrics.Total = Math.Round(double.Parse(totalMemoryParts[1]) / 1024, 0);
  307. metrics.Free = Math.Round(double.Parse(freeMemoryParts[1]) / 1024, 0);//m
  308. metrics.Used = metrics.Total - metrics.Free;
  309. return metrics;
  310. }
  311. /// <summary>
  312. /// Unix系统获取
  313. /// </summary>
  314. /// <returns></returns>
  315. public static MemoryMetrics GetUnixMetrics()
  316. {
  317. string output = ShellUtil.Bash("awk '/MemTotal/ {total=$2} /MemAvailable/ {available=$2} END {print total,available}' /proc/meminfo");
  318. var metrics = new MemoryMetrics();
  319. var memory = output.Split(' ', (char)StringSplitOptions.RemoveEmptyEntries);
  320. if (memory.Length != 2) return metrics;
  321. metrics.Total = double.Parse(memory[0]) / 1024;
  322. metrics.Free = double.Parse(memory[1]) / 1024;
  323. metrics.Used = metrics.Total - metrics.Free;
  324. return metrics;
  325. }
  326. /// <summary>
  327. /// macOS系统获取
  328. /// </summary>
  329. /// <returns></returns>
  330. public static MemoryMetrics GetMacOSMetrics()
  331. {
  332. var metrics = new MemoryMetrics();
  333. //物理内存大小
  334. var total = ShellUtil.Bash("sysctl -n hw.memsize | awk '{printf \"%.2f\", $1/1024/1024}'");
  335. metrics.Total = float.Parse(total.Replace("%", string.Empty));
  336. //TODO:占用内存,检查效率
  337. var free = ShellUtil.Bash("top -l 1 -s 0 | awk '/PhysMem/ {print $6+$8}'");
  338. metrics.Free = float.Parse(free);
  339. metrics.Used = metrics.Total - metrics.Free;
  340. return metrics;
  341. }
  342. }
  343. public class ShellUtil
  344. {
  345. /// <summary>
  346. /// linux 系统命令
  347. /// </summary>
  348. /// <param name="command"></param>
  349. /// <returns></returns>
  350. public static string Bash(string command)
  351. {
  352. var escapedArgs = command.Replace("\"", "\\\"");
  353. var process = new Process()
  354. {
  355. StartInfo = new ProcessStartInfo
  356. {
  357. FileName = "/bin/bash",
  358. Arguments = $"-c \"{escapedArgs}\"",
  359. RedirectStandardOutput = true,
  360. UseShellExecute = false,
  361. CreateNoWindow = true,
  362. }
  363. };
  364. process.Start();
  365. string result = process.StandardOutput.ReadToEnd();
  366. process.WaitForExit();
  367. process.Dispose();
  368. return result;
  369. }
  370. /// <summary>
  371. /// windows CMD 系统命令
  372. /// </summary>
  373. /// <param name="fileName"></param>
  374. /// <param name="args"></param>
  375. /// <returns></returns>
  376. public static string Cmd(string fileName, string args)
  377. {
  378. var info = new ProcessStartInfo
  379. {
  380. FileName = fileName,
  381. Arguments = args,
  382. RedirectStandardOutput = true
  383. };
  384. var output = string.Empty;
  385. using (var process = Process.Start(info))
  386. {
  387. output = process.StandardOutput.ReadToEnd();
  388. }
  389. return output;
  390. }
  391. /// <summary>
  392. /// Windows POWERSHELL 系统命令
  393. /// </summary>
  394. /// <param name="script"></param>
  395. /// <returns></returns>
  396. public static string PowerShell(string script)
  397. {
  398. using var PowerShellInstance = System.Management.Automation.PowerShell.Create();
  399. PowerShellInstance.AddScript(script);
  400. var PSOutput = PowerShellInstance.Invoke();
  401. var output = new StringBuilder();
  402. foreach (var outputItem in PSOutput)
  403. {
  404. output.AppendLine(outputItem.BaseObject.ToString());
  405. }
  406. return output.ToString();
  407. }
  408. }
  409. public class ShellHelper
  410. {
  411. /// <summary>
  412. /// Linux 系统命令
  413. /// </summary>
  414. /// <param name="command"></param>
  415. /// <returns></returns>
  416. public static string Bash(string command)
  417. {
  418. var escapedArgs = command.Replace("\"", "\\\"");
  419. var process = new Process()
  420. {
  421. StartInfo = new ProcessStartInfo
  422. {
  423. FileName = "/bin/bash",
  424. Arguments = $"-c \"{escapedArgs}\"",
  425. RedirectStandardOutput = true,
  426. UseShellExecute = false,
  427. CreateNoWindow = true,
  428. }
  429. };
  430. process.Start();
  431. string result = process.StandardOutput.ReadToEnd();
  432. process.WaitForExit();
  433. process.Dispose();
  434. return result;
  435. }
  436. /// <summary>
  437. /// Windows CMD 系统命令
  438. /// </summary>
  439. /// <param name="fileName"></param>
  440. /// <param name="args"></param>
  441. /// <returns></returns>
  442. public static string Cmd(string fileName, string args)
  443. {
  444. var info = new ProcessStartInfo
  445. {
  446. FileName = fileName,
  447. Arguments = args,
  448. RedirectStandardOutput = true
  449. };
  450. var output = string.Empty;
  451. using (var process = Process.Start(info))
  452. {
  453. output = process.StandardOutput.ReadToEnd();
  454. }
  455. return output;
  456. }
  457. /// <summary>
  458. /// Windows POWERSHELL 系统命令
  459. /// </summary>
  460. /// <param name="script"></param>
  461. /// <returns></returns>
  462. public static string PowerShell(string script)
  463. {
  464. using var PowerShellInstance = System.Management.Automation.PowerShell.Create();
  465. PowerShellInstance.AddScript(script);
  466. var PSOutput = PowerShellInstance.Invoke();
  467. var output = new StringBuilder();
  468. foreach (var outputItem in PSOutput)
  469. {
  470. output.AppendLine(outputItem.BaseObject.ToString());
  471. }
  472. return output.ToString();
  473. }
  474. }