场景:公司写的程序老是崩掉,查原因无果,各种改版无果,遂写一个守护程序来监听该程序,如果崩掉,就自动重启。
1. 添加进程管理类 ProcessHelper
using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Guard { public class ProcessHelper { /// <summary> /// 查看进程是否存在 /// </summary> /// <param name="name">进程名称</param> /// <returns></returns> public static bool Exist(string name) { return Process.GetProcessesByName(name).Length > 0; } /// <summary> /// 开启进程 /// </summary> /// <param name="path">进程所在物理路径</param> /// <returns></returns> public static void Start(string path) { Process m_Process = new Process(); m_Process.StartInfo.FileName = path; //开启新的窗体 m_Process.StartInfo.UseShellExecute = true; m_Process.Start(); } /// <summary> /// 关闭进程 /// </summary> /// <param name="name">进程名称</param> /// <returns></returns> public static void Stop(string name) { Process proc = Process.GetProcessesByName(name).FirstOrDefault(); if (proc != null) proc.Kill(); } } }
2. 添加配置文件 App.config
<?xml version="1.0" encoding="utf-8" ?> <configuration> <appSettings> <!--守护间隔时间--> <add key="second" value="10"/> <!--守护程序端口--> <add key="port" value="104"/> <!--守护程序路径--> <add key="path" value="D:\项目文件\_报告影像自助系统\trunk\DicomPrintDesktopV3\bin\Debug\LZIMC.ReportPrintSystem.DicomPrintDesktopV3.exe"/> </appSettings> </configuration>
3. 在类型库里面添加引用 System.configuration,方便获取配置文件自定义的值
4. 实现代码
using System; using System.Collections.Generic; using System.Configuration; using System.IO; using System.Linq; using System.Net; using System.Net.NetworkInformation; using System.Text; using System.Threading; namespace Guard { class Program { static void Main(string[] args) { try { int second = Convert.ToInt32(ConfigurationManager.AppSettings["second"]); int port = Convert.ToInt32(ConfigurationManager.AppSettings["port"]); string path = ConfigurationManager.AppSettings["path"]; while (true) { Console.WriteLine("Port: " + port + " status: " + (PortInUse(port) ? "存在" : "不存在")); if (!PortInUse(port)) //如果监听的端口不存在,就启动对应的程序 { WriteLog("启动端口" + port + "的程序"); ProcessHelper.Start(path); } Thread.Sleep(second * 1000); } } catch (Exception ex) { WriteLog("发生错误:" + ex.Message); } } /// <summary> /// 日志记录 /// </summary> /// <param name="errMsg"></param> private static void WriteLog(string errMsg) { string sFilePath = AppDomain.CurrentDomain.BaseDirectory + "\\Log"; string sFileName = DateTime.Now.ToString("yyyy-MM-dd") + ".log"; sFileName = sFilePath + "\\" + sFileName; Directory.CreateDirectory(sFilePath); FileStream fs; StreamWriter sw; if (File.Exists(sFileName)) fs = new FileStream(sFileName, FileMode.Append, FileAccess.Write); else fs = new FileStream(sFileName, FileMode.Create, FileAccess.Write); sw = new StreamWriter(fs); sw.WriteLine("时间:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); sw.WriteLine("信息:" + errMsg); sw.WriteLine(""); sw.Close(); fs.Close(); } /// <summary> /// 判断端口是否占用 /// </summary> /// <param name="port"></param> /// <returns></returns> public static bool PortInUse(int port) { bool inUse = false; IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties(); IPEndPoint[] ipEndPoints = ipProperties.GetActiveTcpListeners(); foreach (IPEndPoint endPoint in ipEndPoints) { if (endPoint.Port == port) { inUse = true; break; } } return inUse; } } }
其他:程序崩掉,但没有自动关闭控制台的窗体,便不能通过端口监听到是否崩掉,遂修改系统注册表:
运行注册表编辑器,依次定位到 HKEY_CURRENT_USER\Software\Microsoft\Windows\WindowsError Reporting,
在右侧窗口中找到并双击打开DontshowUI,然后在弹出的窗口中将默认值“0”修改为“1”。 那么,当程序崩溃时,就不会再出现”xx程序已停止工作”的提示框,崩溃程序进程会自动退出。 这种修改系统注册表的方法是最方便和直接的,但会对所有程序生效。
如图: