2011-02-01 149 views
46

我創建了一個名爲ProxyMonitor的Windows服務,而我目前正在按照我想要的方式安裝和卸載服務。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()我只是將running變量更改爲false;

我需要怎麼做才能使服務不斷活躍,因爲我將需要監控網絡我需要跟蹤變化等


更新:1

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

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

ThreadWorker我有ProxyEventLogger.WriteEntry("Main thread entered")哪些不會被解僱。

+0

`線程=新主題(ThreadWorker)`不會工作 – 2011-02-01 16:10:05

+0

工作完全正常,爲什麼你認爲它會失敗? – RobertPitt 2011-02-01 22:37:45

回答

117

OnStart()回調需要及時返回,因此您需要開始執行所有工作的線程。我會建議增加以下字段類:

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

_thread場將保留對您的OnStart()回調創建System.Threading.Thread對象的引用。 _shutdownEvent字段包含系統級別的事件結構,該結構將用於指示線程在服務關閉時停止運行。

OnStart()回調中,創建並啓動您的線程。

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

您需要一個名爲WorkerThreadFunc的函數才能使其工作。它必須匹配System.Threading.ThreadStart代表簽名。

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循環檢查ManualResetEvent以查看它是否「設置」。由於我們在上面初始化了對象false,所以此檢查返回false。在圈內,我們睡了1秒。您需要將其替換爲您需要執行的工作 - 監視代理設置等。

最後,在您的Windows服務的OnStop()回調中,想要發信號通知線程停止運行。這很容易使用_shutdownEvent

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

希望這會有所幫助。

0

爲什麼不在您的Windows Service類型的解決方案中創建一個新項目?這設置了您需要實現的所有結構,包括用於服務啓動/停止事件的處理程序。

+1

這部分是一種培訓體驗,我更願意從底層學習它的做法。 – RobertPitt 2011-02-01 15:52:54

+0

我認爲,即使是培訓(尤其是培訓?),您最好學習如何爲Windows服務創建腳手架,然後瞭解它爲什麼可以工作以及它如何工作。而不是自下而上,正如你所發現的那樣,更令人沮喪。 – 2011-02-01 16:03:13

6

您需要退出您的OnStart處理程序,以便服務控制器意識到您的服務實際已啓動。爲了使它像你想要的那樣工作,你可以啓動一個計時器,該計時器在一個時間間隔內進行打勾並在打勾時進行處理。

編輯:

嘗試把一個System.Diagnostics.Debugger.Launch()在你的OnStart,看看發生了什麼(將斷點設置在ThreadWorker)。我建議在#if DEBUG中包裝這個以確保它不會被部署。

我也意識到,你不給你Thread一個名字:

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

當然不是在OnStart方法添加while循環。這將對操作系統說服務尚未啓動,因爲它無法從OnStart方法安全地退出。我通常會創建一個在OnStart方法中啓用的Timer。然後在Ticks方法中,我確實調用了必要的方法以便讓應用程序運行。

或者,你可以做到以下幾點:

// 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服務的更多信息,你可以得到一個骨架例子here

1

使用控制檯應用演示的示例代碼。希望這將有助於..

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.. 
      } 

     } 
    } 
}