Windows hizmeti program aracılığıyla kendini nasıl yeniden başlatabilir?


Yanıtlar:


187

Başarısızlıktan sonra hizmeti yeniden başlatacak şekilde ayarlayın (kontrol panelinde hizmeti çift tıklatın ve bu sekmelere bir göz atın - adını unuttum). Ardından, hizmetin yeniden başlatılmasını istediğinizde, sadece arayın Environment.Exit(1)(veya sıfır olmayan herhangi bir dönüş) ve işletim sistemi sizin için yeniden başlatacaktır.


7
Konum hizmetler panelinde, söz konusu hizmeti sağ tıklatın ve özellikleri seçin, ardından kurtarma sekmesini seçin.
James Michael Hare

20
Bunun istenen davranışı nasıl sağladığını görüyorum, ancak 1 dönüş kodu sisteme bir hata olduğunu söylemek içindir. Aslında bir hata yoksa ve hizmetinizi yeniden başlatmak istiyorsanız bu kötü uygulama değil mi?
mgttlinger

4
Bu, kurulumdan sonra olayda servis yükleyici tarafından programlı olarak yapılabilir, tıklamanıza gerek yoktur ... Hizmetiniz uzak bir sunucudaysa ve örneğin test sırasında günde birkaç kez kurmanız gerekiyorsa?
Dean Kuga

5
@mgttlinger: Bence evet, hizmetiniz sağlıklı olduğunda kötü bir uygulamadır, bu yüzden asla yeniden başlatılması gerekmez. Ancak bazı hizmet mimarisi erişemeyiz ve yeniden başlatılması gerekiyorsa iyi olmadığının bir belirtisidir, bu yüzden bazı minimum kaynakları (mümkünse) kapatmak ve serbest bırakmak ve 'ayaklarını kesmek' için sorun yoktur. yanlış çalışan servis daha kötü (işe yaramaz) olabilir.
Luciano

5
@JohnLeidegren Eğer düzgün bir kapatma istiyorsanız , servis kurtarma ayar ekranında 'Hatalı duraklamalar için eylemleri etkinleştir' onay kutusunu etkinleştirerek ayarlayabilir Service.ExitCode = 1ve sonra çalıştırabilirsiniz Service.Stop(). Bu şekilde yapılması uygun bir kapanmaya izin verir ve yine de yeniden başlatmayı tetikler.
Chris Rice

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
Boşluklar içeriyorsa, hizmet adınızın yanına "" eklemeyi unutmayın.
apc

4
Bu sadece ayrıcalıklı hesap altında çalışan hizmetler içindir, ki bu zaten kötü bir fikirdir.
Dmitry Gusarov

Ortamınıza bağlı olarak, cmd.exe işleminin ayrı bir işlem grubunda çalıştığından emin olmanız gerekebilir. Bunu uygulamaya çalıştım, ancak "net stop" yürütüldüğünde cmd.exe alt işlemi öldü. Bundan kaçınmak için CREATE_NEW_PROCESS_GROUP belirtilmiş olarak CreateProcess'i aramanız gerekir.
Joppe

17

Hizmetinizin altında çalıştığı kullanıcı hesabının, hizmeti durdurma ve yeniden başlatma izinlerine sahip olduğundan bile emin olamazsınız.


Her ne kadar + 1-ed aynı sorunla karşı karşıya olsa da, sc.exe'ye bakarken, OpenSCManager () çağrılırken dwDesiredAccess olarak SERVICE_QUERY_CONFIG kullandığını ve ardından SERVICE_START ile OpenService () öğesini çağırdığı ortaya çıkıyor. SERVICE_STOP belirli bir hizmeti açmak için ve bu Tamam çalışıyor (erişim ile sorun yok). Bunun .NET'te nasıl yapılabileceğinden emin değilim.
n0p

Çoğu Windows Hizmeti Sistem olarak çalışır, bu nedenle sorun olmamalıdır.
Anahtarı

@ NETWORK SERVICE altında çalıştırılan ve varsayılan olarak kendi yürütülebilir dosyasını açma haklarına sahip olmayan çok büyük bir hizmet döngüsü var.
AgentFire

@AgentFire, doğru, ancak varsayılan AĞ HİZMETİ değil Yerel Sistem'dir. Yerel Sistem, yerel Yöneticiler grubunun üyelerine atananları aşarak, işletim sistemi için doğal olarak en yüksek ayrıcalık düzeyine sahiptir.
Anahtarı

@Switch ancak mevcut en yüksek ayrıcalıkları kullanmak PoL-Prensibini ihlal ediyor .
AgentFire

12

Kendinizi yeniden başlatan bir DOS komut istemi olan bir işlem oluşturabilirsiniz:

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

Bu, başka bir şey yapmadan, çağıran evrenin güvenlik bağlamını devralır ... ve yeniden başlatmak için yeterli beygir gücüne sahip bir bağlam olduğu sürece, iyisinizdir.
kil

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

nerede SERVICENAMEhizmetinizin adıdır (hizmet adındaki boşlukları hesaba katmak için çift tırnak işareti kullanılır, aksi takdirde atlanabilir).

Temiz, otomatik yeniden başlatma yapılandırması gerekmez.


9
& vs && hakkında yeni bir şeyler öğrendim: [command1] & [command2] her iki komutu da her zaman sırayla yürütürken [command1] && [command2], command2 yalnızca komut1 başarıyla çalışırsa çalışır ( autoitscript.com/forum/topic/… )
Jeffrey Knight

5

Neden kendini yeniden başlatmasını istediğinize bağlı olacaktır.

Hizmetin periyodik olarak kendini temizlemesinin bir yolunu arıyorsanız, periyodik olarak bir temizleme rutinine neden olan hizmette çalışan bir zamanlayıcı olabilir.

Hata durumunda yeniden başlatmanın bir yolunu arıyorsanız - servis ana bilgisayarı kurulum sırasında bu yeteneği sağlayabilir.

Peki neden sunucuyu yeniden başlatmanız gerekiyor? Ne elde etmeye çalışıyorsunuz?


1
Büyük Nesne Yığını ve bellek parçalanması ile ilgileniyorsanız bu işe yaramaz. Sözde .NET 4 / 4.5 ve 64 bit süreçleri bu konuda çok yardımcı oldu.
David Kassa

3

Kendi kendine yeten bir hizmette yapabileceğinizi sanmıyorum (Yeniden Başlat'ı çağırdığınızda, Yeniden Başlat komutunu kesecek hizmeti durduracak ve bir daha başlatılmayacaktır). İkinci bir .exe (ServiceManager sınıfını kullanan bir Konsol uygulaması) ekleyebiliyorsanız, bağımsız .exe dosyasını başlatarak hizmeti yeniden başlatmasını ve sonra çıkmasını sağlayabilirsiniz.

İkinci düşüncede, muhtemelen hizmeti başlatmak için bir Zamanlanmış Görev kaydettirebilirsiniz (örneğin, 'at' komutunu kullanarak) ve sonra kendi kendine durmasını sağlayabilirsiniz; muhtemelen işe yarar.


3

Bir toplu iş dosyasına veya EXE'e bombardıman sorunu, bir hizmetin harici uygulamayı çalıştırmak için gerekli izinlere sahip olabileceği veya olmayabilir.

Bulduğum bunu yapmanın en temiz yolu, Hizmet Denetim Yöneticisi'nin giriş noktası olan OnStop () yöntemini kullanmaktır. Ardından, tüm temizleme kodunuz çalışır ve durma kodunuzun işini yaptığını varsayarak, herhangi bir asılı sokete veya başka işleme sahip olmazsınız.

Bunu yapmak için, OnStop yöntemine bir hata kodu ile çıkmasını söyleyen sonlandırmadan önce bir bayrak ayarlamanız gerekir; SCM, hizmetin yeniden başlatılması gerektiğini bilir. Bu bayrak olmadan hizmeti SCM'den manuel olarak durduramazsınız. Bu, hizmeti bir hatayla yeniden başlayacak şekilde ayarladığınızı varsayar.

İşte benim durdurma kodu:

...

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);
}

Hizmet bir sorunla karşılaşırsa ve yeniden başlatılması gerekirse, hizmeti SCM'den durduran bir iş parçacığı başlatırım. Bu, hizmetin kendisinden sonra temizlenmesini sağlar:

...

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

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

2

Hizmetinizin yeniden başlatılmasını zamanlamak için Windows Zamanlayıcı'yı kullanırdım. Sorun şu ki, kendinizi yeniden başlatamazsınız, ancak kendinizi durdurabilirsiniz. (Esasen, oturduğunuz şubeyi gördünüz ... benzetimimi alırsanız) Bunu sizin için yapmak için ayrı bir işleme ihtiyacınız var. Windows Zamanlayıcı uygun bir programdır. Hemen yürütmek için hizmetinizi (hizmetin içinden bile olsa) yeniden başlatmak üzere bir kerelik bir görev zamanlayın.

Aksi takdirde, bunu sizin için yapan bir "çobanlık" işlemi oluşturmanız gerekir.


2

Soruna ilk yanıt en basit çözümdür: "Environment.Exit (1)" Bunu Windows Server 2008 R2 üzerinde kullanıyorum ve mükemmel çalışıyor. Hizmet kendini durdurur, O / S 1 dakika bekler, sonra yeniden başlatır.


Ne kadar bekleyeceği, ne kadar bekleyeceğinize bağlıdır. Ancak varsayılan 1 dakikadır, ancak birisi yanıtınızın yanlış bir izlenim vermesini istemiyorsa.
Espen

1

Yapabileceğini sanmıyorum. Bir hizmet "durdurulduğunda" tamamen boşalır.

Tamam, sanırım her zaman bir yolum var. Örneğin, hizmeti durdurmak, yeniden başlatmak ve sonra çıkmak için ayrılmış bir işlem oluşturabilirsiniz.


0

Daha iyi bir yaklaşım, NT Service'i uygulamanız için bir sarıcı olarak kullanmak olabilir. NT Hizmeti başlatıldığında, uygulamanız komutun başlamasını bekleyen (veya otomatik olarak başlayacak şekilde yapılandırılmış) bir "boşta" modunda başlayabilir.

Bir araba düşünün, çalıştırıldığında boşta başlar, komutunuzun ileri veya geri gitmesini bekler. Bu, uygulamanızı nasıl açığa çıkaracağınızı seçebileceğinizden daha iyi uzaktan yönetim gibi diğer avantajlara da izin verir.


0

Sadece geçen: ve bazı ekstra bilgi eklemek düşündüm ...

Ayrıca bir istisna atabilirsiniz, bu otomatik olarak Windows hizmetini kapatacak ve otomatik yeniden başlatma seçenekleri sadece tekme. Bu konuda tek sorun, PC'nizde bir dev çevreniz varsa, o zaman JIT tekmelemeye çalışır, ve hata ayıklama Y / N diyerek bir uyarı alırsınız. hayır deyin ve sonra kapanacak ve düzgün bir şekilde yeniden başlayacaktır. (JIT olmayan bir bilgisayarda sadece hepsi çalışır). neden im trolling, bu JIT Win 7 (XP ile iyi çalışmak için kullanılan) yeni ve ben JIT devre dışı bırakmanın bir yolunu bulmaya çalışırken yeni .... ben burada belirtilen Environment.Exit yöntemi deneyebilirsiniz bu da işe yarıyor.

Kristian: Bristol, İngiltere


3
Tüm bu istisna, çıkış (1) çözümlerinin hepsi uygulamanın düzgün temizlenmesini önler. Zarif olmayan bir şekilde çıkmak kötü bir çözümdür
devshorts

0

Bunun gibi bir restart.bat dosyası oluşturun

@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%

Ardından% service% hizmetiniz başladığında% taskname% görevini silin


0

Uygulama kodunu barındırmak için ayrı bir uygulama alanı oluşturun. Yeniden başlatma gerektiğinde, işlem yerine uygulama alanını kaldırabilir ve yeniden yükleyebiliriz (Windows hizmeti). IIS uygulama havuzu bu şekilde çalışır, asp.net uygulamasını doğrudan çalıştırmazlar, ayrı uygulama alanı kullanırlar.


-2

En kolay yol, bir toplu iş dosyasına sahip olmaktır:

net stop net başlatma

ve dosyayı istediğiniz zaman aralığıyla zamanlayıcıya ekleyin


Çalışmıyor çünkü toplu iş her iki komut arasında durduruldu, çünkü hizmetin kendisinin bir alt süreci.
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();
        }
    }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.