首先介绍下守护进程的基本概念,守护进程是一个在后台运行并且不受任何终端控制的进程,它的作用就是守护某个程序异常关闭后,通过守护进程将其自动启动起来(服务器部署WebApi/WebService部署)。而本文介绍的守护进程属于控制类程序进程,它通过检测程序的一些事件或采集的数据,将当前守护的程序直接结束。这类软件可能出现的场景在于网络游戏或者公司限制某些软件使用,网络游戏中守护进程发现某些游戏特定数据异常(数据查询或配置获取)将当前游戏进程直接关闭,并弹窗提示给用户,还有公司如需限制员工使用某类软件,通过进程查看限制某些软件程序是否使用,进行后序一系列操作并记录。

    下面介绍下这类守护进程公司使用的软件架构吧,我是这么设计的首先需要开发一个Client客户端(主程序)用于查杀用户进程,接着需要创建一个Windows服务(用于守护Client客户端被异常结束再次启动用)、然后需要一个WebApi(用于后台数据交互处理),最后需要数据库(记录数据)。其中主程序是基于C# winform开发的,Client客户端启动需要获取管理员权限(用于一些特定操作),客户端管理员身份启动代码如下:

//当前用户是管理员的时候,直接启动应用程序
//如果不是管理员,则使用启动对象启动程序,以确保使用管理员身份运行
//获得当前登录的Windows用户标示
System.Security.Principal.WindowsIdentity identity = System.Security.Principal.WindowsIdentity.GetCurrent();
System.Security.Principal.WindowsPrincipal principal = new System.Security.Principal.WindowsPrincipal(identity);
//判断当前登录用户是否为管理员
if (principal.IsInRole(System.Security.Principal.WindowsBuiltInRole.Administrator))
{
    //如果是管理员,则直接运行
    string current_directory_path_1 = 程序路径;
    Application.Run(new 窗体名());
}
else
{
  //创建启动对象
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.UseShellExecute = true;
startInfo.WorkingDirectory = Environment.CurrentDirectory;
startInfo.FileName = Application.ExecutablePath;
//设置启动动作,确保以管理员身份运行
startInfo.Verb = "runas";
try
{
 System.Diagnostics.Process.Start(startInfo);
}
catch
 {
   return;
}
//退出
Application.Exit();

因为检查行为是时时或者定时的任务,所以程序中需要使用Timer组件用于定时启动监测。当检测到异常数据,可弹窗提示或者结束对应进程。我这边使用的结束进程方法是通过cmd Dos命令结束进程,下面是使用方法:

//用CMD方式执行DOS命令
        public static string CmdCommand(string command)
        {
            //方法1
            //    //实例一个Process类,启动一个独立进程
            //    Process p = new Process();
            //    //Process类有一个StartInfo属性
            //    //设定程序名
            //    p.StartInfo.FileName = "cmd.exe";
            //    //设定程式执行参数 
            //    p.StartInfo.Arguments = "/c " + command;
            //    //关闭Shell的使用 
            //    p.StartInfo.UseShellExecute = false;
            //    //重定向标准输入 
            //    p.StartInfo.RedirectStandardInput = true;
            //    p.StartInfo.RedirectStandardOutput = true;
            //    //重定向错误输出 
            //    p.StartInfo.RedirectStandardError = true;
            //    //设置不显示窗口
            //    p.StartInfo.CreateNoWindow = true;
            //    //启动
            //    p.Start();
            //    //也可以用这种方式输入要执行的命令
            //    //不过要记得加上Exit要不然下一行程式执行的时候会当机
            //    //p.StandardInput.WriteLine(command);
            //    //p.StandardInput.WriteLine("exit"); 
            //    //从输出流取得命令执行结果
            //    // LogHelper.Testwrite(command);
            //    LogHelper.Testwrite(p.StandardOutput.ReadToEnd());
            //    return p.StandardOutput.ReadToEnd();

            //方法2
            Process pro = new Process();
            //string ll = string.Empty;
            try
            {
                pro = new Process();
                pro.StartInfo.FileName ="cmd.exe";              //cmd  
                pro.StartInfo.UseShellExecute = false;          //不显示shell  
                pro.StartInfo.CreateNoWindow = true;            //不创建窗口  
                pro.StartInfo.RedirectStandardInput = true;     //打开流输入  
                pro.StartInfo.RedirectStandardOutput = true;    //打开流输出  
                pro.StartInfo.RedirectStandardError = true;     //打开错误流  
                pro.Start();//执行  
                pro.StandardInput.WriteLine(command + "&exit"); //&exit运行完立即退出  
                pro.StandardInput.AutoFlush = true;             //清缓存  
                //ll = pro.StandardOutput.ReadToEnd();            //读取输出  
                //LogHelper.Testwrite("cmd执行成功");
                pro.WaitForExit();                              //等待程序执行完退出进程    
                pro.Close();//结束    
                return null;
            }
            catch //(Exception ex)
            {
                LogHelper.Testwrite("cmd执行失败");
                return null;
            }
        }

下面是调用方法,当然可以使用任何DOS命令(全局结束进程)。

CmdCommand("taskkill /f /im xxx.exe");

判断进程方法如下:

//判断进程项
        public int JuageProcess(string Processname)
        { 
try
            {
                int ProcessCount = System.Diagnostics.Process.GetProcessesByName("程序进程名").ToList().Count;
                if (ProcessCount > 1)
                {
                    return 1;
                }
                else
                {
                    return 0;
                }
            }
            catch (Exception ex)
            {
                 throw ex;
            }
}

为了确保程序能够更好的使用,我们这边也需要让客户端跟windows服务都需要系统开机自动启动的功能,也可以调用上述方法,输入对应的DOS命令即可,注:为了让用户不能删除这个项,可以通过定时任务用于查看这些启动项,如被删除可以设置添加等操作。程序启动也需要简单的保护自身的方法,如隐藏守护进程的目录文件夹。

    本人水平有限,以上仅个人的一些经验,与大家分享一起学习。