Windows服务如何以编程方式自行重启?


Answers:


187

将服务设置为在失败后重新启动(双击控制面板中的服务,然后在这些选项卡上四处查看-我忘记了它的名称)。然后,只要您想重新启动服务,只需调用Environment.Exit(1)(或任何非零返回),操作系统就会为您重新启动。


7
位置在服务面板中,右键单击有问题的服务并选择属性,然后选择恢复选项卡。
詹姆斯·迈克尔·哈尔

20
我看到这是如何实现所需的行为的,但是返回码为1意味着告诉系统有错误。如果实际上没有错误,而您只是想重新启动服务,这不是不好的做法吗?
mgttlinger

4
可以通过服务安装程序在安装后事件中以编程方式完成此操作,无需单击四处。如果您的服务位于远程服务器上,并且您需要一天多次安装(例如在测试期间),该怎么办?
Dean Kuga 2013年

5
@mgttlinger:我认为是的,当您的服务运行状况良好时,这是一种不好的做法,因此永远不需要重新启动它。但是某些服务体系结构超出了我们的承受范围,如果需要重新启动它们,这是一个不适的症状,因此关闭并释放一些最小资源(如果可能)并“割脚”是没有问题的,因为离开了服务运行不当可能会变得更糟(无用)。
卢西亚诺

5
@JohnLeidegren如果要适当关闭,可以设置Service.ExitCode = 1,然后执行Service.Stop()并在服务恢复设置屏幕上启用“为错误停止操作启用”复选框。以这种方式执行此操作可以允许正确关闭并仍然触发重新启动。
克里斯·赖斯

22
Dim proc As New Process()
Dim psi As New ProcessStartInfo()

psi.CreateNoWindow = True
psi.FileName = "cmd.exe"
psi.Arguments = "/C net stop YOURSERVICENAMEHERE && net start YOURSERVICENAMEHERE"
psi.LoadUserProfile = False
psi.UseShellExecute = False
psi.WindowStyle = ProcessWindowStyle.Hidden
proc.StartInfo = psi
proc.Start()

3
如果服务名称包含空格,请记住添加“”。
2015年

4
这仅适用于在特权帐户下运行的服务,这是个坏主意。
德米特里·古萨罗夫

17

您无法确定您的服务所运行的用户帐户是否具有停止和重新启动服务的权限。


尽管我遇到了同样的问题,但是+1的问题,但在查看sc.exe时,发现它在调用OpenSCManager()时使用SERVICE_QUERY_CONFIG作为dwDesiredAccess,然后使用SERVICE_START | SERVICE_STOP打开一个特定的服务,它工作正常(访问没有问题)。不确定如何在.NET中完成此操作。
n0p

大多数Windows服务都是作为系统运行的,因此这不是问题。
切换

@Switch在网络服务下运行着大量的服务,默认情况下,这些服务甚至没有权限打开自己的可执行文件。
AgentFire '19

@AgentFire,正确,但默认值为本地系统,而不是网络服务。本地系统固有地具有操作系统的最高特权级别-超过了分配给本地Administrators组成员的特权。
切换

@Switch但是使用最可用的特权违反了PoL-Principle
AgentFire '19

12

您可以创建一个进程来重新启动自己的DOS命令提示符:

 Process process = new Process();
 process.StartInfo.FileName = "cmd";
 process.StartInfo.Arguments = "/c net stop \"servicename\" & net start \"servicename\"";
 process.Start();

这样,无需执行任何其他操作,即可继承调用线程的安全上下文...只要该上下文具有足够的重启能力,就可以了。
Clay

12
const string strCmdText = "/C net stop \"SERVICENAME\"&net start \"SERVICENAME\"";
Process.Start("CMD.exe", strCmdText);

SERVICENAME服务的名称在哪里(包含双引号以说明服务名称中的空格,否则可以省略)。

干净,不需要自动重新启动配置。


9
了解了&vs &&的新知识:[command1]&[command2]将始终按顺序执行两个命令,而[command1] && [command2]仅在command1成功运行时才运行command2(autoitscript.com/forum/topic/…
Jeffrey

5

这取决于您为什么要使其自行重启。

如果您只是在寻找一种定期清除服务的方法,则可以在服务中运行一个计时器,该计时器会定期导致清除例程。

如果您正在寻找一种在故障后重新启动的方法,则服务主机本身可以在设置时提供该功能。

那么,为什么需要重新启动服务器?您想达到什么目的?


1
如果您担心大对象堆和内存碎片,这将无法正常工作。据说.NET 4 / 4.5和64位进程对此起到了很大作用。
大卫·卡萨

3

我认为您不能在独立的服务中使用(当您调用Restart时,它将停止该服务,这将中断Restart命令,并且永远不会再次启动)。如果您可以添加第二个.exe(使用ServiceManager类的控制台应用程序),则可以启动独立的.exe并让其重新启动服务,然后退出。

再次考虑,您可能让服务注册了计划任务(例如,使用命令行“ at”命令)以启动服务,然后使其自身停止;那可能会工作。


3

炮轰到批处理文件或EXE的问题是,服务可能具有或不具有运行外部应用程序所需的权限。

我发现最干净的方法是使用OnStop()方法,它是服务控制管理器的入口点。然后,所有清除代码都将运行,并且假设您的停止代码正在执行其工作,那么您将没有任何挂起的套接字或其他进程。

为此,您需要在终止之前设置一个标志,该标志告知OnStop方法以错误代码退出。则SCM知道该服务需要重新启动。没有此标志,您将无法从SCM手动停止服务。这也假定您已将服务设置为在发生错误时重新启动。

这是我的停止码:

...

bool ABORT;

protected override void OnStop()
{
    Logger.log("Stopping service");
    WorkThreadRun = false;
    WorkThread.Join();
    Logger.stop();
    // if there was a problem, set an exit error code
    // so the service manager will restart this
    if(ABORT)Environment.Exit(1);
}

如果服务出现问题并需要重新启动,我将启动一个线程,以从SCM停止该服务。这使服务可以自行清理:

...

if(NeedToRestart)
{
    ABORT = true;
    new Thread(RestartThread).Start();
}

void RestartThread()
{
    ServiceController sc = new ServiceController(ServiceName);
    try
    {
        sc.Stop();
    }
    catch (Exception) { }
}

2

我将使用Windows Scheduler计划重新启动服务。问题是您无法重新启动自己,但可以停止自己。(从本质上讲,您已经割断了所坐的分支……如果您得到我的类比),您需要一个单独的过程来为您完成此工作。Windows Scheduler是合适的。安排一次任务以重新启动您的服务(甚至从服务本身内部)以立即执行。

否则,您将必须创建一个为您完成的“牧羊”过程。


2

对这个问题的第一个回答是最简单的解决方案:“ Environment.Exit(1)”我正在Windows Server 2008 R2上使用它,它可以完美运行。服务会自行停止,操作系统等待1分钟,然后重新启动。


等待多长时间取决于您将其设置为等待多长时间。默认值是1分钟,但是如果有人不希望您的回答给人留下错误的印象。
Espen

1

我不认为可以。当服务“停止”时,它将完全卸载。

好吧,好吧,我总有一种方法。例如,您可以创建一个独立的进程来停止该服务,然后重新启动它,然后退出。


0

更好的方法可能是将NT服务用作应用程序的包装。启动NT服务时,您的应用程序可以以“空闲”模式启动,以等待命令启动(或配置为自动启动)。

想想一辆汽车,当它启动时,它以空转状态开始,等待命令前进或后退。这还带来了其他好处,例如更好的远程管理,因为您可以选择如何公开应用程序。


0

刚刚过去:我以为我会添加一些额外的信息...

您还可以引发异常,这将自动关闭Windows服务,并且自动重新启动选项也会启动。唯一的问题是,如果您的PC上有开发环境,那么JIT会尝试启动,并且您将得到提示说调试是/否。说不,然后它将关闭,然后重新正确启动。(在没有JIT的PC上,一切正常。)触发的原因是,此JIT是Win 7的新功能(它以前在XP等环境下可以正常工作),并且正在尝试寻找一种禁用JIT的方法...。我可以尝试这里提到的Environment.Exit方法,看看如何也可以。

克里斯蒂安:英国布里斯托尔


3
所有这些都引发异常,exit(1)解决方案都避免对应用程序进行适当的清理。
不适当

0

像这样创建一个restart.bat文件

@echo on
set once="C:\Program Files\MyService\once.bat"
set taskname=Restart_MyService
set service=MyService
echo rem %time% >%once%
echo net stop %service% >>%once%
echo net start %service% >>%once%
echo del %once% >>%once%

schtasks /create /ru "System" /tn %taskname% /tr '%once%' /sc onstart /F /V1 /Z
schtasks /run /tn %taskname%

然后在%service%启动时删除任务%taskname%


0

创建一个单独的appdomain来托管应用程序代码。需要重新启动时,我们可以卸载并重新加载appdomain而不是进程(Windows服务)。这就是IIS应用程序池的工作方式,它们不直接运行asp.net应用程序,而是使用单独的appdmain。


-2

最简单的方法是使用以下文件创建批处理文件:

净停止净开始

并以所需的时间间隔将文件添加到调度程序


它不起作用,因为批处理在两个命令之间都停止了,因为它是服务本身的子进程。
Orabîg

-3
private static void  RestartService(string serviceName)
    {
        using (var controller = new ServiceController(serviceName))
        {
            controller.Stop();
            int counter = 0;
            while (controller.Status != ServiceControllerStatus.Stopped)
            {
                Thread.Sleep(100);
                controller.Refresh();
                counter++;
                if (counter > 1000)
                {
                    throw new System.TimeoutException(string.Format("Could not stop service: {0}", Constants.Series6Service.WindowsServiceName));
                }
            }

            controller.Start();
        }
    }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.