一、概述

        有时候存在这样一个需求,我们需要对某个进程进行监控,如该进程是否启动,该进程是否正常运行等,这个需求类似于嵌入式中的看门狗,负责在特定情况下启动或关闭服务。

        本文基于C#语言,使用Process类实现上述对进程进行监控的功能。

二、实现:

        Process类提供对本地和远程进程的访问权限并使你能够启动和停止本地系统进程。Process组件是一个有用的工具,可用于启动、停止、控制和监视应用。基于Process类,我们可以实现对进程进行监控的服务,如下所示:

class Program
    {
        private static Process[] processList; //进程列表
        private static Process myProcess;     //我要监控的进程
        private static string processName = "DataRSNetty";  //监听的进程的名称
        private static string startProcess = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory + @"BIN\DataRSNetty.exe");  //获取程序的基目录

        static void Main(string[] args)
        {
            //程序以管理员身份启动。
            /**
             * 当前用户是管理员的时候,直接启动应用程序
             * 如果不是管理员,则使用启动对象启动程序,以确保使用管理员身份运行
             */
            //获得当前登录的Windows用户标识
            System.Security.Principal.WindowsIdentity identity = System.Security.Principal.WindowsIdentity.GetCurrent();
            System.Security.Principal.WindowsPrincipal principal = new System.Security.Principal.WindowsPrincipal(identity);

            //Automatically configures the log4net system based on the application's configuration settings
            XmlConfigurator.Configure();

            //判断当前登录用户是否为管理员
            if (principal.IsInRole(System.Security.Principal.WindowsBuiltInRole.Administrator))
            {
                //TimeSpan workStartDT = DateTime.Parse("23:52:08").TimeOfDay;
                //TimeSpan workEndDT = DateTime.Parse("23:52:10").TimeOfDay;
                //设置开机自启动。
                //AutoStart(true);   //开机自启动

                while (true)
                {
                    //尝试从后台获取监视的线程,以判断监听的进程是否打开
                    myProcess = GetProcess(processName);
                    if (myProcess != null)
                    {
                        try
                        {
                            //进程已经打开,获取所要监听的进程
                            判断该进程占用的内存
                            //long processMem = myProcess.PrivateMemorySize64 / (1024 * 1024);
                            PerformanceCounter myMemory = new PerformanceCounter("Process", "Working Set - Private", myProcess.ProcessName);  //该操作比较占用CUP
                            float processMem = myMemory.NextValue() / (1024 * 1024);
                            //判断内存
                            if (processMem > 800)//如果进程内存大于800,则干掉该进程,重新开始。
                            {
                                KillProcess(processName);
                                LogHelper.Error("进程DataRSNetty内存超出800M,重启该进程!");
                            }

                        }
                        catch
                        {
                            //该错误可能是:被监听的进程已经结束,但是还没重启的时候。计算此进程所占的内存。
                            //真正的原因没有测试。
                            //通过测试,确实是这样。
                            //打开要监听的进程
                            LogHelper.Error("监控程序发生错误!该错误可能是:被监听的进程已经结束,但是还没重启的时候。计算此进程所占的内存。");
                            if (StartProcess(startProcess))
                            {
                                LogHelper.Info($"进程{processName}重启成功!");
                            }
                        }
                        //线程休眠1秒钟
                        Thread.Sleep(1000);
                    }
                    else
                    {
                        //打开要监听的进程
                        if (StartProcess(startProcess))
                        {
                            LogHelper.Info($"进程{processName}重启成功!");
                        }
                    }
                }
            }
            else
            {
                //请以管理员身份运行。
                //MessageBox.Show("请以管理员身份运行!");
                LogHelper.Info("请以管理员身份运行进程监控程序!");
            }
        }


        /// <summary>
        /// 打开某个进程
        /// </summary>
        /// <param name="processName"></param>
        /// <returns></returns>
        public static bool StartProcess(string processName)
        {
            myProcess = new Process();                //实例化一个进程
            myProcess.StartInfo.WorkingDirectory = System.AppDomain.CurrentDomain.BaseDirectory + @"BIN"; //指定工作目录
            myProcess.StartInfo.FileName = processName;
            myProcess.StartInfo.UseShellExecute = false;
            //myProcess.StartInfo.RedirectStandardInput = true;
            try
            {
                //判断进程是否打开
                if (myProcess.Start())
                {
                    //Console.WriteLine("进程打开成功!");
                    LogHelper.Info("进程启用成功!");
                    return true;    //进程打开
                }
            }
            catch
            {
                //系统找不到指定文件
                LogHelper.Error("系统找不到指定文件!");
                return false;
            }
            return false;          //进程没有打开
        }

        /// <summary>
        /// 判断监听的进程是否打开
        /// </summary>
        /// <returns>判断的进程</returns>
        public static Process GetProcess(string processName)
        {
            processList = System.Diagnostics.Process.GetProcesses();    //获取后台进程
            foreach (Process p in processList)
            {
                if (p.ProcessName == processName)
                {
                    myProcess = p;
                    return myProcess;    //返回要监听的进程
                }
            }
            return null;  //要监听的进程并没有打开,返回null
        }

        /// <summary>
        /// 关闭进程
        /// </summary>
        /// <param name="strProcessesByName"></param>
        public static void KillProcess(string strProcessesByName)//关闭进程
        {
            foreach (Process p in Process.GetProcesses())        //循环所有的进程
            {
                if (p.ProcessName == strProcessesByName)
                {
                    try
                    {
                        p.Kill();
                        p.WaitForExit(); // possibly with a timeout
                    }
                    catch (Win32Exception e)
                    {
                        // process was terminating or can't be terminated - deal with it   //进程正在中止
                        //Console.WriteLine(e.Message.ToString());
                        LogHelper.Error(e.Message.ToString());
                    }
                    catch (InvalidOperationException e)
                    {
                        // process has already exited - might be able to let this one go   
                        //Console.WriteLine(e.Message.ToString());
                        LogHelper.Error(e.Message.ToString());
                    }
                }

            }
        }

         
    }

        上述程序实现了对某个特定进程的监控,被监听的进程名称以及路径在代码开始进行了设置。该程序的功能是首先尝试从后台获取被监视的进程,以判断进程是否在运行,若进程没有在运行,则启动该被监视的进程。若该进程已经运行了,则计算该进程所占用的内存大小,若大于800M,可能内存泄漏,则关闭掉该进程,进程会在接下来的循环中被重启。

三、结束

        本文给出了一个基于微软提供的Process类实现的进程监控服务,用于对某一进程进行启动或关闭,该服务类似于看门狗或进程守护者。