首先介绍下守护进程的基本概念,守护进程是一个在后台运行并且不受任何终端控制的进程,它的作用就是守护某个程序异常关闭后,通过守护进程将其自动启动起来(服务器部署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命令即可,注:为了让用户不能删除这个项,可以通过定时任务用于查看这些启动项,如被删除可以设置添加等操作。程序启动也需要简单的保护自身的方法,如隐藏守护进程的目录文件夹。
本人水平有限,以上仅个人的一些经验,与大家分享一起学习。