using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using NewLife;
using NewLife.Caching;
namespace Stardust.Models
{
/// <summary>进程信息</summary>
public class AppInfo
{
#region 属性
/// <summary>进程标识</summary>
public Int32 Id { get; set; }
/// <summary>进程名称</summary>
public String Name { get; set; }
/// <summary>版本</summary>
public String Version { get; set; }
/// <summary>用户名</summary>
public String UserName { get; set; }
/// <summary>机器名</summary>
public String MachineName { get; set; }
/// <summary>开始时间</summary>
public DateTime StartTime { get; set; }
/// <summary>处理器时间。单位ms</summary>
public Int32 ProcessorTime { get; set; }
/// <summary>物理内存</summary>
public Int64 WorkingSet { get; set; }
/// <summary>线程数</summary>
public Int32 Threads { get; set; }
/// <summary>句柄数</summary>
public Int32 Handles { get; set; }
/// <summary>连接数</summary>
public Int32 Connections { get; set; }
private readonly Process _process;
#endregion
#region 构造
/// <summary>实例化进程信息</summary>
public AppInfo() { }
/// <summary>根据进程对象实例化进程信息</summary>
/// <param name="process"></param>
public AppInfo(Process process)
{
try
{
Id = process.Id;
Name = process.ProcessName;
if (Name == "dotnet" || "*/dotnet".IsMatch(Name)) Name = GetProcessName(process);
//StartTime = process.StartTime;
//ProcessorTime = (Int64)process.TotalProcessorTime.TotalMilliseconds;
_process = process;
Refresh();
}
catch (Win32Exception) { }
catch (InvalidOperationException) { }
}
#endregion
#region 方法
/// <summary>刷新进程相关信息</summary>
public void Refresh()
{
try
{
_process.Refresh();
WorkingSet = _process.WorkingSet64;
Threads = _process.Threads.Count;
Handles = _process.HandleCount;
UserName = Environment.UserName;
MachineName = Environment.MachineName;
StartTime = _process.StartTime;
ProcessorTime = (Int32)_process.TotalProcessorTime.TotalMilliseconds;
try
{
// 调用WindowApi获取进程的连接数
var tcps = NetHelper.GetAllTcpConnections();
if (tcps != null && tcps.Length > 0)
{
var pid = Process.GetCurrentProcess().Id;
Connections = tcps.Count(e => e.ProcessId == pid);
}
}
catch { }
}
catch (Win32Exception) { }
}
private static ICache _cache = new MemoryCache();
/// <summary>获取进程名</summary>
/// <param name="process"></param>
/// <returns></returns>
public static String GetProcessName(Process process)
{
if (Runtime.Linux)
{
try
{
var lines = File.ReadAllText($"/proc/{process.Id}/cmdline").Trim('\0', ' ').Split('\0');
if (lines.Length > 1) return lines[1];
}
catch { }
}
else if (Runtime.Windows)
{
// 缓存,避免频繁执行
var key = process.Id + "";
if (_cache.TryGetValue<String>(key, out var value)) return value;
try
{
var dic = ReadWmic("process", "processId=" + process.Id, "commandline");
if (dic.TryGetValue("commandline", out var str))
{
//XTrace.WriteLine(str);
var p = str.IndexOf('\"');
if (p >= 0)
{
var p2 = str.IndexOf('\"', p + 1);
if (p2 > 0) str = str.Substring(p2 + 1);
}
//XTrace.WriteLine(str);
var ss = str.Split(' ');
if (ss.Length >= 2)
{
_cache.Set(key, ss[1], 600);
return ss[1];
}
}
}
catch { }
_cache.Set(key, process.ProcessName, 600);
}
return process.ProcessName;
}
/// <summary>通过WMIC命令读取信息</summary>
/// <param name="type"></param>
/// <param name="where"></param>
/// <param name="keys"></param>
/// <returns></returns>
public static IDictionary<String, String> ReadWmic(String type, String where, params String[] keys)
{
var dic = new Dictionary<String, String>(StringComparer.OrdinalIgnoreCase);
var args = $"{type} where {where} get {keys.Join(",")} /format:list";
var str = Execute("wmic", args)?.Trim();
if (str.IsNullOrEmpty()) return dic;
var ss = str.Split(Environment.NewLine);
foreach (var item in ss)
{
var ks = item.Split("=");
if (ks != null && ks.Length >= 2)
{
var k = ks[0].Trim();
var v = ks[1].Trim();
if (dic.TryGetValue(k, out var val))
dic[k] = val + "," + v;
else
dic[k] = v;
}
}
// 排序,避免多个磁盘序列号时,顺序变动
foreach (var item in dic)
{
if (item.Value.Contains(','))
dic[item.Key] = item.Value.Split(',').OrderBy(e => e).Join();
}
return dic;
}
private static String Execute(String cmd, String arguments = null)
{
try
{
var psi = new ProcessStartInfo(cmd, arguments)
{
// UseShellExecute 必须 false,以便于后续重定向输出流
UseShellExecute = false,
RedirectStandardOutput = true
};
var process = Process.Start(psi);
if (!process.WaitForExit(3_000))
{
process.Kill();
return null;
}
return process.StandardOutput.ReadToEnd();
}
catch { return null; }
}
#endregion
}
}
|