ComputerUtil.cs 16 KB

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