当前位置: 首页 > 工具软件 > Topshelf > 使用案例 >

C# .NET Core3.0+TopShelf 搭建服务程序 实现进程守护技术

祁修诚
2023-12-01

利用windows services实现进程守护功能

一、基本概念

守护进程(daemon)是一类在后台运行的特殊进程,用于执行特定的系统任务。很多守护进程在系统引导的时候启动,并且一直运行直到系统关闭。另一些只在需要的时候才启动,完成任务后就自动结束。
按照服务类型分为如下几个。
1.系统守护进程:syslogd、login、crond、at等。
2.网络守护进程:sendmail、httpd、xinetd、等。
3.独立启动的守护进程:httpd、named、xinetd等。
4.被动守护进程(由xinetd启动):telnet、finger、ktalk等。
实际上进程守护的应用是比较广泛的,如果你的程序需要一直运行,就会需要进程守护,本人的实际应用主要是一些大屏看板、数据服务中心,以及其他的一些需要一直运行的后台程序,都可能会需要到进程守护,因为你要确保这些程序一直运行,不能因为其他一些特殊情况导致异常退出。

二、Topshelf 简单便捷搭建windows services

进程守护技术内容比较多,但是我们应用到的其实比较简单。当然利用windows services做进程守护一定最适合的,这里windows services的概念就不多说了,网上有具体的说明。只是特别说明一下,如果直接使用Net提供的windows services也没问题,实现相对也不复杂,本人在测试的时候发现原版的windows services部署的时候比较麻烦,需要用到Net framwork
的install安装器,不是很方便,可以利用bat脚本实现一键安装,但是也有很多问题,后来就没有继续做下去了。所以了解了一下Topshlef第三方框架, 能够快速的搭建windows services,亲测使用很方便。Topshelf 是一个用来部署基于.NET Framework 开发的服务框架。简化服务创建于部署过程,并且支持控制台应用程序部署为服务。在官方对它介绍就是Puts your app,实际上可以实现一个宿主程序,这个程序可以成为services,也可以成为Console等等具体概念就不多说了。这里我们采用的.Net core3.0实现Topshelf的服务搭建。具体可参考:https://www.cnblogs.com/swjian/p/11498808.html,里面有具体的搭建入门,这里就不在啰嗦了,基本流程都一样,这里特比说明一下windows services的安装和卸载,在上述文章中使用的Net core 2.0,安装services的时候需要用到TopshelfDemo.exe,但是在3.0版本已经不要了,只需要用cmd就可以实现安装卸载,这里为大家提供两个已经写好的bat脚本:
安装:
安装脚本看着比较多,前面其实就是的就是为了获取管理员权限,确保服务能够正常安装启动,大家使用的时候只需要把eMDCDataDefend替换成自己的即可。

@echo off
title GetAdministratorPower
mode con cols=100 lines=20
color 3f

:: 开始获取管理员权限
setlocal
set uac=~uac_permission_tmp_%random%
md "%SystemRoot%\system32\%uac%" 2>nul
if %errorlevel%==0 ( rd "%SystemRoot%\system32\%uac%" >nul 2>nul ) else (
    echo set uac = CreateObject^("Shell.Application"^)>"%temp%\%uac%.vbs"
    echo uac.ShellExecute "%~s0","","","runas",1 >>"%temp%\%uac%.vbs"
    echo WScript.Quit >>"%temp%\%uac%.vbs"
    "%temp%\%uac%.vbs" /f
    del /f /q "%temp%\%uac%.vbs" & exit )
endlocal
:: 完成获取,下面可以开始写你自己的代码了


echo "install eMDCDataDefend"

@echo off  
sc query eMDCDataDefend |findstr /i "STATE">nul
:: 如果服务已安装,跳转至exist标签;如果未安装,跳转至notexist标签
if not errorlevel 1 (goto exist) else goto notexist 

:notexist
echo "eMDCDataDefend is NOT installed, INSTALLING..."
%~dp0eMDCDataDefend.exe install
sc start eMDCDataDefend
goto end  
  
:exist
echo "eMDCDataDefend is Installed, checking..."
sc query |find /i "eMDCDataDefend" >nul 2>nul  
:: 如果服务已启动,跳转至end标签;如果未启动,跳转至stopped标签
if not errorlevel 1 (goto end) else goto stoppped  

:stoppped
echo "eMDCDataDefend is NOT started, STARTING..."
sc start eMDCDataDefend
goto end  
  
:end  
echo "install finished!"
pause 

卸载:
轻松卸载services服务。

@echo off
title GetAdministratorPower
mode con cols=100 lines=20
color 3f

:: 开始获取管理员权限
setlocal
set uac=~uac_permission_tmp_%random%
md "%SystemRoot%\system32\%uac%" 2>nul
if %errorlevel%==0 ( rd "%SystemRoot%\system32\%uac%" >nul 2>nul ) else (
    echo set uac = CreateObject^("Shell.Application"^)>"%temp%\%uac%.vbs"
    echo uac.ShellExecute "%~s0","","","runas",1 >>"%temp%\%uac%.vbs"
    echo WScript.Quit >>"%temp%\%uac%.vbs"
    "%temp%\%uac%.vbs" /f
    del /f /q "%temp%\%uac%.vbs" & exit )
endlocal
:: 完成获取,下面可以开始写你自己的代码了


echo "uninstall eMDCDataDefend"

@echo off  
echo "eMDCDataDefend Detect service running status..."
sc query |find /i "eMDCDataDefend" >nul 2>nul  
:: 如果服务已启动,跳转至end标签;如果未启动,跳转至stopped标签
if not errorlevel 1 (goto stoped) else goto notStoppped  

:notStoppped
echo "eMDCDataDefend uninstall..."
%~dp0eMDCDataDefend.exe uninstall
goto end  
  
:stoped  
echo "eMDCDataDefend stoped  and uninstall..."
sc stop eMDCDataDefend
%~dp0eMDCDataDefend.exe uninstall
goto end  

:end
echo "eMDCDataDefend uninstall is finished..."
pause 

到现在一个windows services服务基本上就可以搭建出来了。关于windows services调试,主要实现一个延时启动就可以了,在程序附加到进程以后才开始工作,就可以用代码调试了。

三、实现进程守护

进程守护的基本实现可以参考:https://blog.csdn.net/struggle_cxg/article/details/83213783 应用比较简单,但是这位兄弟说的比较详细,我这里说明几点问题:
1.进程守护也可以实现双进程互锁,主要为了适应某些极为苛刻的环境,一般用处不大,有一个进程守护足够了。
2.进程守护可以守护后台程序,但是如果是前台程序,由守护程序启动后是没有界面的,就是你的界面程序完全没有意义的,在上述文章中是有解决方案的,但是本人并不推荐, 因为这样很奇怪,后台程序只用来实现后台服务,和前台有关联,本来就不是很合理。所以如果是后台程序尽量就做成没有界面的。但是我确实也遇见需要界面,就是我们所谓的大屏展示,需要界面一直有,那么这种方式其实使用windows 计划任务+bat实现就好了,不要搞得这么复杂。
具体参考:
①Windows Server2012/2018 定时任务设置及执行失败的解决方法
https://blog.csdn.net/qianxing111/article/details/80015702
②Win7的任务计划怎么是后台运行的,怎么设置能让任务前台运行?
https://blog.csdn.net/u013600225/article/details/49882931/
然后配上一个简单的bat启动脚本:
好了,这样就可以实现大屏展示的进程守护了。千万不要把问题复杂化。

@echo off
echo "eMDC+ Restart"
taskkill /F /IM eMDC+.exe
echo "eMDC+ Stop"
timeout /t 5 >nul
start /d ".\" eMDC+.exe
echo "eMDC+ Start"
exit

最后配上本人写的一段进程守护的具体实现代码,请大家参考:

 class Program
    {//服务为自动运行
        static void Main(string[] args)
        {
            try
            {
                HostFactory.Run(x =>            //1
                {
                    x.Service<Service>(s =>     //2
                    {
                        s.ConstructUsing(name => new Service()); //3
                        s.WhenStarted(tc => tc.Start());  //4
                        s.WhenStopped(tc => tc.Stop());    //5
                    });
                    x.RunAsLocalSystem();        //6
                    x.SetDescription("服务描述");    //7
                    x.SetDisplayName("Myservices"); //8  
                    x.SetServiceName("Myservices"); //9 
                });
            }
            catch (Exception)
            {
                // ignored
            }
        }
    }

    public class Service
    {
        private  Timer timer=null;

        public void Start()
        {
            timer=new Timer(RestartProcess,null,30000,10000);
        }

        public void Stop()
        {
            //To do something
        }

      
        private void RestartProcess(object state)
        {
            Process[] processes = Process.GetProcessesByName("ApplicationName");
            if (processes.Length==0) 
            {
                Process proc = new Process
                {
                    StartInfo =
                    {
                        CreateNoWindow =false,
                        UseShellExecute = false,
                        RedirectStandardError = true,
                        RedirectStandardInput = true,
                        RedirectStandardOutput = true,
                        FileName = "ApplicationFileName",
                        WorkingDirectory ="WorkingDirectory",
                    }
                };
                try
                {
                    proc.Start();
                }
                catch (Exception)
                {
                    // ignored
                }
            }
        }
    }

有问题欢迎留言交流。

四、守护进程应用情况

1.目前现场实际应用来说,进程守护和数据服务软件应当有一个信息交互过程,确保数据服务软件在正常运行,考虑几种进程间的通讯方式,最后还是选择了Socket的通信方式来实现数据通讯。
2.双进程互锁机制可能还有需要,如果客户有极端需求的情况下,可能还是要考虑一下。

 类似资料: