ComputerUtil.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  1. // 麻省理工学院许可证
  2. //
  3. // 版权所有 (c) 2021-2023 zuohuaijun,大名科技(天津)有限公司 联系电话/微信:18020030720 QQ:515096995
  4. //
  5. // 特此免费授予获得本软件的任何人以处理本软件的权利,但须遵守以下条件:在所有副本或重要部分的软件中必须包括上述版权声明和本许可声明。
  6. //
  7. // 软件按“原样”提供,不提供任何形式的明示或暗示的保证,包括但不限于对适销性、适用性和非侵权的保证。
  8. // 在任何情况下,作者或版权持有人均不对任何索赔、损害或其他责任负责,无论是因合同、侵权或其他方式引起的,与软件或其使用或其他交易有关。
  9. namespace Admin.NET.Core;
  10. public static class ComputerUtil
  11. {
  12. /// <summary>
  13. /// 内存信息
  14. /// </summary>
  15. /// <returns></returns>
  16. public static MemoryMetrics GetComputerInfo()
  17. {
  18. MemoryMetricsClient client = new();
  19. MemoryMetrics memoryMetrics;
  20. if (IsMacOS())
  21. {
  22. memoryMetrics = client.GetMacOSMetrics();
  23. }
  24. else if (IsUnix())
  25. {
  26. memoryMetrics = client.GetUnixMetrics();
  27. }
  28. else
  29. {
  30. memoryMetrics = client.GetWindowsMetrics();
  31. }
  32. memoryMetrics.FreeRam = Math.Round(memoryMetrics.Free / 1024, 2) + "GB";
  33. memoryMetrics.UsedRam = Math.Round(memoryMetrics.Used / 1024, 2) + "GB";
  34. memoryMetrics.TotalRam = Math.Round(memoryMetrics.Total / 1024, 2) + "GB";
  35. memoryMetrics.RamRate = Math.Ceiling(100 * memoryMetrics.Used / memoryMetrics.Total).ToString() + "%";
  36. memoryMetrics.CpuRate = Math.Ceiling(GetCPURate().ParseToDouble()) + "%";
  37. return memoryMetrics;
  38. }
  39. /// <summary>
  40. /// 获取正确的操作系统版本(Linux获取发行版本)
  41. /// </summary>
  42. /// <returns></returns>
  43. public static String GetOSInfo()
  44. {
  45. string opeartion = string.Empty;
  46. if (IsMacOS())
  47. {
  48. var output = ShellHelper.Bash("sw_vers | awk 'NR<=2{printf \"%s \", $NF}'");
  49. if (output != null)
  50. {
  51. opeartion = output.Replace("%", string.Empty);
  52. }
  53. }
  54. else if (IsUnix())
  55. {
  56. var output = ShellHelper.Bash("awk -F= '/^VERSION_ID/ {print $2}' /etc/os-release | tr -d '\"'");
  57. opeartion = output ?? string.Empty;
  58. }
  59. else
  60. {
  61. opeartion = RuntimeInformation.OSDescription;
  62. }
  63. return opeartion;
  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 = ShellHelper.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 == null || disk.Length < 5)
  81. continue;
  82. var diskInfo = new DiskInfo()
  83. {
  84. DiskName = disk[0],
  85. TypeName = ShellHelper.Bash("diskutil info " + disk[0] + " | awk '/File System Personality/ {print $4}'").Replace("\n", string.Empty),
  86. TotalSize = long.Parse(disk[1]) / 1024,
  87. Used = long.Parse(disk[2]) / 1024,
  88. AvailableFreeSpace = long.Parse(disk[3]) / 1024,
  89. AvailablePercent = decimal.Parse(disk[4].Replace("%", ""))
  90. };
  91. diskInfos.Add(diskInfo);
  92. }
  93. }
  94. else if (IsUnix())
  95. {
  96. var output = ShellHelper.Bash(@"df -mT | awk '/^\/dev\/(sd|vd|xvd|nvme|sda|vda)/ {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 == null || disk.Length < 6)
  106. continue;
  107. var diskInfo = new DiskInfo()
  108. {
  109. DiskName = disk[0],
  110. TypeName = disk[1],
  111. TotalSize = long.Parse(disk[2]) / 1024,
  112. Used = long.Parse(disk[3]) / 1024,
  113. AvailableFreeSpace = long.Parse(disk[4]) / 1024,
  114. AvailablePercent = decimal.Parse(disk[5].Replace("%", ""))
  115. };
  116. diskInfos.Add(diskInfo);
  117. }
  118. }
  119. else
  120. {
  121. var driv = DriveInfo.GetDrives().Where(u => u.IsReady);
  122. foreach (var item in driv)
  123. {
  124. if (item.DriveType == DriveType.CDRom) continue;
  125. var obj = new DiskInfo()
  126. {
  127. DiskName = item.Name,
  128. TypeName = item.DriveType.ToString(),
  129. TotalSize = item.TotalSize / 1024 / 1024 / 1024,
  130. AvailableFreeSpace = item.AvailableFreeSpace / 1024 / 1024 / 1024,
  131. };
  132. obj.Used = obj.TotalSize - obj.AvailableFreeSpace;
  133. obj.AvailablePercent = decimal.Ceiling(obj.Used / (decimal)obj.TotalSize * 100);
  134. diskInfos.Add(obj);
  135. }
  136. }
  137. return diskInfos;
  138. }
  139. /// <summary>
  140. /// 获取外网IP地址
  141. /// </summary>
  142. /// <returns></returns>
  143. public static string GetIpFromOnline()
  144. {
  145. var url = "https://www.ip.cn/api/index?ip&type=0";
  146. var str = url.GetAsStringAsync().GetAwaiter().GetResult();
  147. var resp = JSON.Deserialize<IpCnResp>(str);
  148. return resp.Ip + " " + resp.Address;
  149. }
  150. public static bool IsUnix()
  151. {
  152. return RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
  153. }
  154. public static bool IsMacOS()
  155. {
  156. return RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
  157. }
  158. public static string GetCPURate()
  159. {
  160. string cpuRate;
  161. if (IsMacOS())
  162. {
  163. string output = ShellUtil.Bash("top -l 1 | grep \"CPU usage\" | awk '{print $3 + $5}'");
  164. cpuRate = output.Trim();
  165. }
  166. else if (IsUnix())
  167. {
  168. string output = ShellUtil.Bash("top -b -n1 | grep \"Cpu(s)\" | awk '{print $2 + $4}'");
  169. cpuRate = output.Trim();
  170. }
  171. else
  172. {
  173. string output = ShellUtil.Cmd("wmic", "cpu get LoadPercentage");
  174. cpuRate = output.Replace("LoadPercentage", string.Empty).Trim();
  175. }
  176. return cpuRate;
  177. }
  178. /// <summary>
  179. /// 获取系统运行时间
  180. /// </summary>
  181. /// <returns></returns>
  182. public static string GetRunTime()
  183. {
  184. string runTime = string.Empty;
  185. if (IsMacOS())
  186. {
  187. //macOS 获取系统启动时间:
  188. //sysctl -n kern.boottime | awk '{print $4}' | tr -d ','
  189. //返回:1705379131
  190. //使用date格式化即可
  191. string output = ShellUtil.Bash("date -r $(sysctl -n kern.boottime | awk '{print $4}' | tr -d ',') +\"%Y-%m-%d %H:%M:%S\"").Trim();
  192. runTime = DateTimeUtil.FormatTime((DateTime.Now - output.ParseToDateTime()).TotalMilliseconds.ToString().Split('.')[0].ParseToLong());
  193. }
  194. else if (IsUnix())
  195. {
  196. string output = ShellUtil.Bash("uptime -s").Trim();
  197. runTime = DateTimeUtil.FormatTime((DateTime.Now - output.ParseToDateTime()).TotalMilliseconds.ToString().Split('.')[0].ParseToLong());
  198. }
  199. else
  200. {
  201. string output = ShellUtil.Cmd("wmic", "OS get LastBootUpTime/Value");
  202. string[] outputArr = output.Split('=', (char)StringSplitOptions.RemoveEmptyEntries);
  203. if (outputArr.Length == 2)
  204. runTime = DateTimeUtil.FormatTime((DateTime.Now - outputArr[1].Split('.')[0].ParseToDateTime()).TotalMilliseconds.ToString().Split('.')[0].ParseToLong());
  205. }
  206. return runTime;
  207. }
  208. }
  209. public class IpCnResp
  210. {
  211. public string Ip { get; set; }
  212. public string Address { get; set; }
  213. }
  214. /// <summary>
  215. /// 内存信息
  216. /// </summary>
  217. public class MemoryMetrics
  218. {
  219. [Newtonsoft.Json.JsonIgnore]
  220. [System.Text.Json.Serialization.JsonIgnore]
  221. public double Total { get; set; }
  222. [Newtonsoft.Json.JsonIgnore]
  223. [System.Text.Json.Serialization.JsonIgnore]
  224. public double Used { get; set; }
  225. [Newtonsoft.Json.JsonIgnore]
  226. [System.Text.Json.Serialization.JsonIgnore]
  227. public double Free { get; set; }
  228. /// <summary>
  229. /// 已用内存
  230. /// </summary>
  231. public string UsedRam { get; set; }
  232. /// <summary>
  233. /// CPU使用率%
  234. /// </summary>
  235. public string CpuRate { get; set; }
  236. /// <summary>
  237. /// 总内存 GB
  238. /// </summary>
  239. public string TotalRam { get; set; }
  240. /// <summary>
  241. /// 内存使用率 %
  242. /// </summary>
  243. public string RamRate { get; set; }
  244. /// <summary>
  245. /// 空闲内存
  246. /// </summary>
  247. public string FreeRam { get; set; }
  248. }
  249. /// <summary>
  250. /// 磁盘信息
  251. /// </summary>
  252. public class DiskInfo
  253. {
  254. /// <summary>
  255. /// 磁盘名
  256. /// </summary>
  257. public string DiskName { get; set; }
  258. /// <summary>
  259. /// 类型名
  260. /// </summary>
  261. public string TypeName { get; set; }
  262. /// <summary>
  263. /// 总剩余
  264. /// </summary>
  265. public long TotalFree { get; set; }
  266. /// <summary>
  267. /// 总量
  268. /// </summary>
  269. public long TotalSize { get; set; }
  270. /// <summary>
  271. /// 已使用
  272. /// </summary>
  273. public long Used { get; set; }
  274. /// <summary>
  275. /// 可使用
  276. /// </summary>
  277. public long AvailableFreeSpace { get; set; }
  278. /// <summary>
  279. /// 使用百分比
  280. /// </summary>
  281. public decimal AvailablePercent { get; set; }
  282. }
  283. public class MemoryMetricsClient
  284. {
  285. /// <summary>
  286. /// windows系统获取内存信息
  287. /// </summary>
  288. /// <returns></returns>
  289. public MemoryMetrics GetWindowsMetrics()
  290. {
  291. string output = ShellUtil.Cmd("wmic", "OS get FreePhysicalMemory,TotalVisibleMemorySize /Value");
  292. var metrics = new MemoryMetrics();
  293. var lines = output.Trim().Split('\n', (char)StringSplitOptions.RemoveEmptyEntries);
  294. if (lines.Length <= 0) return metrics;
  295. var freeMemoryParts = lines[0].Split('=', (char)StringSplitOptions.RemoveEmptyEntries);
  296. var totalMemoryParts = lines[1].Split('=', (char)StringSplitOptions.RemoveEmptyEntries);
  297. metrics.Total = Math.Round(double.Parse(totalMemoryParts[1]) / 1024, 0);
  298. metrics.Free = Math.Round(double.Parse(freeMemoryParts[1]) / 1024, 0);//m
  299. metrics.Used = metrics.Total - metrics.Free;
  300. return metrics;
  301. }
  302. /// <summary>
  303. /// Unix系统获取
  304. /// </summary>
  305. /// <returns></returns>
  306. public MemoryMetrics GetUnixMetrics()
  307. {
  308. string output = ShellUtil.Bash("free -m | awk '{print $2,$3,$4,$5,$6}'");
  309. var metrics = new MemoryMetrics();
  310. var lines = output.Split('\n', (char)StringSplitOptions.RemoveEmptyEntries);
  311. if (lines.Length <= 0) return metrics;
  312. if (lines != null && lines.Length > 0)
  313. {
  314. var memory = lines[1].Split(' ', (char)StringSplitOptions.RemoveEmptyEntries);
  315. if (memory.Length >= 3)
  316. {
  317. metrics.Total = double.Parse(memory[0]);
  318. metrics.Used = double.Parse(memory[1]);
  319. metrics.Free = double.Parse(memory[2]);//m
  320. }
  321. }
  322. return metrics;
  323. }
  324. /// <summary>
  325. /// macOS系统获取
  326. /// </summary>
  327. /// <returns></returns>
  328. public MemoryMetrics GetMacOSMetrics()
  329. {
  330. var metrics = new MemoryMetrics();
  331. //物理内存大小
  332. var total = ShellUtil.Bash("sysctl -n hw.memsize | awk '{printf \"%.2f\", $1/1024/1024}'");
  333. metrics.Total = float.Parse(total.Replace("%", string.Empty));
  334. //TODO:占用内存,检查效率
  335. var free = ShellUtil.Bash("top -l 1 -s 0 | awk '/PhysMem/ {print $6+$8}'");
  336. metrics.Free = float.Parse(free);
  337. metrics.Used = metrics.Total - metrics.Free;
  338. return metrics;
  339. }
  340. }
  341. public class ShellUtil
  342. {
  343. /// <summary>
  344. /// linux 系统命令
  345. /// </summary>
  346. /// <param name="command"></param>
  347. /// <returns></returns>
  348. public static string Bash(string command)
  349. {
  350. var escapedArgs = command.Replace("\"", "\\\"");
  351. var process = new Process()
  352. {
  353. StartInfo = new ProcessStartInfo
  354. {
  355. FileName = "/bin/bash",
  356. Arguments = $"-c \"{escapedArgs}\"",
  357. RedirectStandardOutput = true,
  358. UseShellExecute = false,
  359. CreateNoWindow = true,
  360. }
  361. };
  362. process.Start();
  363. string result = process.StandardOutput.ReadToEnd();
  364. process.WaitForExit();
  365. process.Dispose();
  366. return result;
  367. }
  368. /// <summary>
  369. /// windows系统命令
  370. /// </summary>
  371. /// <param name="fileName"></param>
  372. /// <param name="args"></param>
  373. /// <returns></returns>
  374. public static string Cmd(string fileName, string args)
  375. {
  376. string output = string.Empty;
  377. var info = new ProcessStartInfo();
  378. info.FileName = fileName;
  379. info.Arguments = args;
  380. info.RedirectStandardOutput = true;
  381. using (var process = Process.Start(info))
  382. {
  383. output = process.StandardOutput.ReadToEnd();
  384. }
  385. return output;
  386. }
  387. }
  388. public class ShellHelper
  389. {
  390. /// <summary>
  391. /// Linux 系统命令
  392. /// </summary>
  393. /// <param name="command"></param>
  394. /// <returns></returns>
  395. public static string Bash(string command)
  396. {
  397. var escapedArgs = command.Replace("\"", "\\\"");
  398. var process = new Process()
  399. {
  400. StartInfo = new ProcessStartInfo
  401. {
  402. FileName = "/bin/bash",
  403. Arguments = $"-c \"{escapedArgs}\"",
  404. RedirectStandardOutput = true,
  405. UseShellExecute = false,
  406. CreateNoWindow = true,
  407. }
  408. };
  409. process.Start();
  410. string result = process.StandardOutput.ReadToEnd();
  411. process.WaitForExit();
  412. process.Dispose();
  413. return result;
  414. }
  415. /// <summary>
  416. /// Windows 系统命令
  417. /// </summary>
  418. /// <param name="fileName"></param>
  419. /// <param name="args"></param>
  420. /// <returns></returns>
  421. public static string Cmd(string fileName, string args)
  422. {
  423. string output = string.Empty;
  424. var info = new ProcessStartInfo();
  425. info.FileName = fileName;
  426. info.Arguments = args;
  427. info.RedirectStandardOutput = true;
  428. using (var process = Process.Start(info))
  429. {
  430. output = process.StandardOutput.ReadToEnd();
  431. }
  432. return output;
  433. }
  434. }