Windows 服务持续运行

Windows Service to run constantly

提问人:RobertPitt 提问时间:2/1/2011 最后编辑:Mark AmeryRobertPitt 更新时间:12/24/2022 访问量:82439

问:

我创建了一个名为 ProxyMonitor 的 Windows 服务,目前正处于按照我想要的方式安装和卸载服务的阶段。

因此,我像这样执行应用程序:

C:\\Windows\\Vendor\\ProxyMonitor.exe /install

不言自明,然后我开始并启动该服务,但是当我这样做时,我收到以下消息:services.msc

本地计算机上的代理监视服务已启动,然后停止。如果没有工作要做,某些服务会自动停止,例如,性能日志和警报服务

我的代码如下所示:

public static Main(string[] Args)
{
    if (System.Environment.UserInteractive)
    {
        /*
            * Here I have my install logic
        */
    }
    else
    {
        ServiceBase.Run(new ProxyMonitor());
    }
}

然后在 ProxyMonitor 类中,我有:

public ProxyMonitor()
{
}

protected override void OnStart(string[] args)
{
    base.OnStart(args);
    ProxyEventLog.WriteEntry("ProxyMonitor Started");

    running = true;
    while (running)
    {
        //Execution Loop
    }
}

我只是将变量更改为onStop()runningfalse;

我需要做些什么才能使服务持续处于活动状态,因为我需要监控网络,我需要跟踪更改等。


更新: 1

protected override void OnStart(string[] args)
{
     base.OnStart(args);
     ProxyEventLog.WriteEntry("ProxyMonitor Started");

     Thread = new Thread(ThreadWorker);
     Thread.Start();
 }

在我没有被解雇的情况下。ThreadWorkerProxyEventLogger.WriteEntry("Main thread entered")

C# Windows 服务

评论


答:

0赞 Gabriel Magana 2/1/2011 #1

为什么不在解决方案中创建一个 Windows 服务类型的新项目?这将设置您需要实现的所有结构,甚至包括服务启动/停止事件的处理程序。

评论

1赞 RobertPitt 2/1/2011
这在一定程度上是一种培训经验,我更愿意从底层学习它的方式。
0赞 Gabriel Magana 2/2/2011
我认为,即使是培训(尤其是培训?),您最好了解 VS 如何为 Windows 服务创建脚手架,然后您可以了解它的工作原理和工作原理。而不是自下而上,正如你所发现的,这更令人沮丧。
0赞 RobertPitt 2/2/2011
这是真的,这一点是有争议的,但这里的情况并非如此。此应用程序已实现 60%,也许在我的下一个应用程序中,我将从 Windows 服务模板开始。
6赞 Mark Avenius 2/1/2011 #2

您需要退出处理程序,以便服务控制器意识到您的服务实际上已启动。为了让它像你想要的那样工作,你可以启动一个计时器,它以一定的时间间隔滴答作响,并在滴答作响时进行处理。OnStart

编辑:

尝试将 System.Diagnostics.Debugger.Launch() 放入 u 中,以查看发生了什么(并在 中放置一个断点)。我建议将其包装起来以确保它不会被部署。OnStartThreadWorker#if DEBUG

我刚刚也意识到你没有给你一个名字:Thread

 Thread myThread = new Thread(ThreadWorker);
 myThread.Start();

评论

0赞 RobertPitt 2/1/2011
应该有任何返回代码,比如 or ,并且线程也可以,对吧?return 0return false
0赞 Mark Avenius 2/1/2011
不;事件处理程序返回 void。只要它在合理的时间范围内退出(我认为大约一分钟),服务控制器就会很高兴。OnStart
2赞 Neil Knight 2/1/2011 #3

当然不会在方法中添加循环。这将告诉操作系统,服务尚未启动,因为它无法安全地退出该方法。我通常会创建一个在方法中启用的。然后在方法中,我确实调用了必要的方法,以便让 appplicatin 运行。whileOnStartOnStartTimerOnStartTicks

或者,您可以执行以下操作:

// The main entry point for the process 
static void Main() 
{ 
    System.ServiceProcess.ServiceBase[] ServicesToRun; 
    ServicesToRun = new System.ServiceProcess.ServiceBase[] { new WinService1() }; 
    System.ServiceProcess.ServiceBase.Run(ServicesToRun); 
} 

有关 Windows 服务的详细信息,可以在此处获取框架示例。

150赞 Matt Davis 2/2/2011 #4

回调需要及时返回,因此您需要启动一个线程,在该线程中将执行所有工作。我建议将以下字段添加到您的班级中:OnStart()

using System.Threading;
private ManualResetEvent _shutdownEvent = new ManualResetEvent(false);
private Thread _thread;

该字段将保存对您在回调中创建的对象的引用。该字段包含一个系统级事件构造,该构造将用于向线程发出信号,使其在服务关闭时停止运行。_threadSystem.Threading.ThreadOnStart()_shutdownEvent

在回调中,创建并启动线程。OnStart()

protected override void OnStart(string[] args)
{
     _thread = new Thread(WorkerThreadFunc);
     _thread.Name = "My Worker Thread";
     _thread.IsBackground = true;
     _thread.Start();
}

您需要一个名为的函数才能正常工作。它必须与 System.Threading.ThreadStart 委托签名匹配。WorkerThreadFunc

private void WorkerThreadFunc()
{
}

如果你不在这个函数中放任何东西,线程将启动,然后立即关闭,所以你必须在里面放一些逻辑,在你做你的工作时基本上保持线程的活跃状态。这就是派上用场的地方。_shutdownEvent

private void WorkerThreadFunc()
{
    while (!_shutdownEvent.WaitOne(0)) {
        // Replace the Sleep() call with the work you need to do
        Thread.Sleep(1000);
    }
}

while 循环检查它是否被“设置”了。由于我们用上面的东西初始化了对象,所以这个检查返回 false。在循环中,我们睡了 1 秒钟。您需要将其替换为您需要执行的工作 - 监视代理设置等。ManualResetEventfalse

最后,在 Windows 服务的回调中,您希望向线程发出停止运行的信号。这很容易使用 .OnStop()_shutdownEvent

protected override void OnStop()
{
     _shutdownEvent.Set();
     if (!_thread.Join(3000)) { // give the thread 3 seconds to stop
         _thread.Abort();
     }
}

评论

0赞 RobertPitt 2/2/2011
谢谢你,我理解了这一切,现在它按预期运行:)
4赞 Matt Davis 2/2/2011
很乐意帮忙。值得一提的是,我有几个详细的 SO 教程,展示了 (1) 如何在事件查看器中拥有自己的日志 (stackoverflow.com/questions/593454/...) 和 (2) 如何在不需要 InstallUtil 的情况下安装/卸载您的服务.exe (stackoverflow.com/questions/1195478/...)。
0赞 RobertPitt 2/2/2011
是的,非常感谢您的帮助,我之前在我寻求胜利的过程中阅读了您的第一篇文章,如果您想查看我的代码,我将其发布在这里并留下了我处于哪个阶段的评论。pastebin.com/t8QQzXC9
1赞 Matt Davis 10/22/2013
@My-Name-Is,示例的组织方式,一旦调用线程,线程将停止执行。那是因为 while 循环将退出。如果要暂停并稍后恢复同一线程,请创建另一个对象来控制线程的该方面。_shutdownEvent.Set()WorkerThreadFunc()ManualResetEvent
1赞 Matt Davis 7/16/2017
@shaikhspear 是的,无论如何都应该是这样。我纠正了它。
3赞 Jayesh Dhananjayan 4/7/2017 #5

使用控制台应用程序演示的示例代码。 希望这会有所帮助。.

 class Program
{
    private static CancellationTokenSource _cancellationTokenSource;
    private static ManualResetEvent _shutdownEvent = new ManualResetEvent(false);
    private static Thread _serviceStartThread;
    private static Thread _serviceStopThread;

    private static int workcounter = 0;
    static void Main(string[] args)
    {

        _cancellationTokenSource = new CancellationTokenSource();
        _serviceStartThread = new Thread(DoWork);
        _serviceStopThread = new Thread(ScheduledStop);
        StartService();
        StopService();
    }

    private static void StartService()
    {
        _serviceStartThread.Start();

    }

    private static void StopService()
    {
        _serviceStopThread.Start();
    }


    /// <summary>
    /// Triggers a cancellation event for stopping the service in a timely fashion.
    /// </summary>
    private static void ScheduledStop()
    {
        while (!_shutdownEvent.WaitOne(0))
        {
            if (workcounter == 10)
            {
                _cancellationTokenSource.Cancel();
            }
        }
    }

    /// <summary>
    /// Represents a long running Task with cancellation option
    /// </summary>
    private static void DoWork()
    {

        while (!_shutdownEvent.WaitOne(0))
        {
            if(!_cancellationTokenSource.Token.IsCancellationRequested)
            {
                workcounter += 1;
                Console.Write(Environment.NewLine);
                Console.Write("Running...counter: " + workcounter.ToString());
                Thread.Sleep(1000);//Not needed, just for demo..
            }
            else
            {
                Console.Write(Environment.NewLine);
                Console.Write("Recieved cancellation token,shutting down in 5 seconds.. counter: " + workcounter.ToString());
                _shutdownEvent.Set();
                Thread.Sleep(5000);//Not needed, just for demo..
            }

        }
    }
}
0赞 S.ATTA.M 1/23/2020 #6

在我看来,解决这个问题的最简单方法是:

protected override void OnStart(string[] args)
{            
    new Task(() =>
    {
            new ProxyMonitor();                    
    }).Start();    
}