前言
在有些特殊项目中,软件可能是无人值守的,如果程序莫名其妙挂了或者进程被干掉了等等,这时开发一个看门狗程序是非常有必要的,它就像一只打不死的小强,只要程序非正常退出,它就能立即再次将被看护的程序启动起来。
代码实现
Tips:文末有完整源代码,就不一步一步写了
1、创建一个Dog类,主要用于间隔性扫描被看护程序是否还在运行
开了个定时器,每5秒去检查1次,如果没有找到进程则使用Process启动程序
publicclassDog{privateTimertimer=newTimer();privatestringprocessName;privatestringfilePath;//要监控的程序的路径publicDog(){=5000;+=timer_Tick;}publicvoidStart(stringfilePath){=filePath;=(filePath);=true;}///summary///定时检测系统是否在运行////summary///paramname="ser"/param///paramname="e"/paramprivatevoidtimer_Tick(objectser,EventArgse){try{Process[]myproc=(processName);if(==0){("检测到看护程序已退出,开始重新激活程序,程序路径:{0}",filePath);ProcessStartInfoinfo=newProcessStartInfo{WorkingDirectory=(filePath),FileName=filePath,UseShellExecute=true};(info);("看护程序已启动");}}catch(Exception){}}}2、在程序入口接收被看护程序的路径,启动Dog扫描
staticclassProgram{staticNotifyIconicon=newNotifyIcon();privatestaticDogdog=newDog();///summary///应用程序的主入口点。////summary[STAThread]staticvoidMain(string[]args){if(args==null||==0){("启动参数异常","提示",,);return;}stringfilePath=args[0];if(!(filePath)){("启动参数异常","提示",,);return;}Processcurrent=();Process[]processes=();//遍历与当前进程名称相同的进程列表foreach(Processprocessinprocesses){//如果实例已经存在则忽略当前进程if(!=){//保证要打开的进程同已经存在的进程来自同一文件路径if(()){//已经存在的进程return;}else{();(3000);}}}="看门狗";=true;("启动看门狗,看护程序:{0}",filePath);(filePath);();}}3、简单实现个日志记录器(使用第三方库也行,建议看护程序最好不要有任何依赖),也可直接使用我下面这个,很简单,无任何依赖
publicclassLog{//读写锁,当资源处于写入模式时,其他线程写入需要等待本次写入结束之后才能继续写入privatestaticReaderWriterLockSlimLogWriteLock=newReaderWriterLockSlim();//日志文件路径publicstaticstringlogPath="logs\\";//静态方法todo:在处理话类型之前自动调用,去检查日志文件是否存在staticLog(){//创建文件夹if(!("logs")){("logs");}}///summary///写入日志.////summarypublicstaticvoidInfo(stringformat,paramsobject[]args){try{();stringmsg=?(format,args):format;using(FileStreamstream=newFileStream(logPath,)){StreamWriterwrite=newStreamWriter(stream);stringcontent=("{0}{1}",("yyyy-MM-ddHH:mm:ss"),msg);(content);//关闭并销毁流写入文件();();}}catch(Exceptione){}finally{();}}}至此,看护程序已经搞定。接着在主程序(被看护程序)封装一个启停类
4、主程序封装看门狗启停类
publicstaticclassWatchDog{privatestaticstringprocessName="WatchDog";//看护程序进程名(注意这里不是被看护程序名,你可以试一下换成主程序名字会使什么效果)privatestaticstringappPath=;//系统启动目录///summary///启动看门狗////summarypublicstaticvoidStart(){try{stringprogram=("{0}{1}.exe",appPath,processName);ProcessStartInfoinfo=newProcessStartInfo{WorkingDirectory=appPath,FileName=program,CreateNoWindow=true,UseShellExecute=true,Arguments=().//被看护程序的完整路径};(info);}catch(Exception){}}///summary///停用看门狗////summarypublicstaticvoidStop(){Process[]myproc=(processName);foreach(Processproinmyproc){();(3000);}}}原理也很简单,其中有两点需要注意:
processName字段表示看护程序,不是被看护程序,如果写反了,嗯(你可以试下效果)‘
Arguments参数是被看护程序的完整路径,因为一般情况下,是由被看护程序启动看护程序,所以我们可以直接使用().获取到被看护程序的完整路径
5、在主程序入口点启动看门狗
publicpartialclassApp:Application{[STAThread]staticvoidMain(){//程序启动前调用看护程序();Applicationapp=newApplication();MainWindowmainWindow=newMainWindow();(mainWindow);}}Winform、普通WPF、Prism等入口点都不太一样,根据项目实际情况灵活处理即可
最后在需要正常退出程序的地方(也就是主程序关闭按钮或其它想要正常退出程序的地方)停止看门狗程序
效果
源代码
后续
在类似地铁进站通道、机场安检通道、口岸出入境通道等等都有一个引导程序,这种比较依赖图形界面的可以尝试使用看门狗程序,看门狗程序不依赖第三方库且代码量较少,一般不会跑飞。
写在最后领取方式:在我的个人主页的第一篇置顶文章中领取