Programování služeb ve Windows - 4.díl

C# .NET Pro pokročilé Programování služeb ve Windows - 4.díl

Začínáme doplňovat Class Server1

Doplníme konstanty a konstruktory :

public partial class Server1 : Component
{
        private const string DISPLAYNAME = "Moje_Service_1";
        private const string PATHFILE =  @"c:\Temp\quotes.txt";
        private const string THREADNAME = "Listener";
        private const string MACHINENAME = ".";         //1
        private const string LOGNAME = "Application";   //2
        private TcpListener listener = null ;
        private int port = 0 ;
        private string filename = String.Empty ;
        private List<string> quotes;
        private Random random;
        private Thread listenerThread = null ;
        private EventLog eventLog1 = new EventLog() ;
        private byte[] buffer;

        public Server1() : this (PATHFILE)              //3
        {
        }
        public Server1(string filename) : this(filename, 7890)  //3
        {
        }

        public Server1(string filename, int port)       //3
        {
                this.filename = filename;
                this.port = port;
                InitializeComponent();
                Init();
                eventLog1.WriteEntry("Konstruktor ", EventLogEntryType.Information); //0
        }

        public void Start()             //4
        {
            ReadQuotes();               //5
            eventLog1.WriteEntry("Start ", EventLogEntryType.Information);      //0 - testovací smazat
            listenerThread = new Thread(new ThreadStart(ListenerThread));       //6
            listenerThread.IsBackground = true;                                 //7
            listenerThread.Name = THREADNAME;                                   //8
            listenerThread.Start();                                             //9
        }

        public void Stop()
        {
            listener.Stop();
        }
        public void Suspend()
        {
            listener.Stop();
        }
        public void Resume()
        {
            Start();
        }
        public void RefreshQuotes()     //10
        {
            ReadQuotes();               //5
        }

        protected void ReadQuotes()     //11
        {
            quotes = new List<string>();
            Stream stream = File.OpenRead(filename);
            StreamReader streamReader = new StreamReader(stream);
            string quote;
            while ((quote = streamReader.ReadLine()) != null)
            {
                quotes.Add(quote);
            }
            streamReader.Close();
            stream.Close();
            random = new Random();
        }

        protected string GetRandomQuoteOfTheDay()       //12
        {
            int index = random.Next(0, quotes.Count);
            return quotes[index];
        }

        protected void ListenerThread()                 //13
        {
            try
            {
                listener = new TcpListener(IPAddress.Loopback, port);   //14

                eventLog1.WriteEntry(IPAddress.Loopback.ToString() + "   " + port.ToString(),
                                        EventLogEntryType.Information);         //0
                listener.Start();                                               //15
                Socket clientSocket = null;
                while (true)                                                    //16
                {
                    if (!listener.Pending())                                    //17
                    {
                        eventLog1.WriteEntry(" Není připojení ", EventLogEntryType.Warning); //0
                    }
                    else
                    {
                        eventLog1.WriteEntry(" Je připijení ", EventLogEntryType.Information);        //0
                        clientSocket = listener.AcceptSocket();                                 //18
                        string message = GetRandomQuoteOfTheDay();                              //19
                        UnicodeEncoding encoder = new UnicodeEncoding();
                        buffer = encoder.GetBytes(message);
                        clientSocket.Send(buffer, buffer.Length, 0);                            //20
                        clientSocket.Close();                                                   //21
                    }
                    Thread.Sleep(1000);                                                         //22

                    //performanceCounterRequestsTotal.Increment();
                    //performanceCounterBytesSentTotal.IncrementBy(buffer.Length);

                    //requestsPerSec++;
                    //bytesPerSec += buffer.Length;
                }
            }
            catch (SocketException ex)
            {
                string message = "Server selhal ve vlákně Listener: " + ex.Message;
                eventLog1.WriteEntry(message, EventLogEntryType.Error);
            }
        }

        [HostProtectionAttribute(SecurityAction.LinkDemand, Synchronization = true)]    //23
        private void Init()
        {
            eventLog1.Log = LOGNAME;
            eventLog1.MachineName = MACHINENAME;
            eventLog1.Source = DISPLAYNAME;
            EventLogTraceListener traceListener = new EventLogTraceListener(eventLog1);
            Trace.Listeners.Add(traceListener);
        }

Popis

  1. lokální PC
  2. získá nebo nastaví název protokolu, kde bude číst nebo zapisovat.
  3. konstruktory
  4. start serveru
  5. načte obsah souboru do kolekce List<string>
  6. příprava nového vlákna
  7. na pozadí
  8. jméno vlákna
  9. start vlákna
  10. nové volání pokud je služba úplná, bude vysvětleno později
  11. načte do quotes[i] obsah souboru
  12. vrací náhodný text i-tého řadku souboru
  13. výkonná část serveru
  14. inicializuje novou instanci TcpListener (127.0.0.1, port)
  15. začne zpracovávat příchozí požadavky na připojení
  16. nekonečná smyčka
  17. určuje, zda jsou požadavky na připojení, čeká na vyřízení, pokud není klient připojen -> false
  18. přijímá žádosti o připojení, čeká na vyřízení
  19. čte náhodný řádek textu souboru
  20. odešle řádek textu na klienta
  21. zavře Socket připojení a uvolní přiřazené zdroje
  22. čeká 1 sekundu, později mohu čas zmenšit
  23. inicializace logu a trastování

Testujeme

  • otevřeme složku WindowsService1 - bin - Instalacni
  • spustíme cmd.exe v režimu administrátora
  • zadáme příkaz Uninstall.bat a pak Install.bat
  • pokud instalace služby proběhne bez závad, zobrazíme si okno služeb
  • spustíme naši službu na 2-5 sekund, pak ji zastavíme
  • nebudeme provádět odinstalování služby!! (to znamená Uninstall.bat)

Naši službu jsme tímto zaregistrovali v databázi služeb a provedli zápis do registru.

Nastavíme TestServeru, MujServerEven­tListener a ClientServer jako exe projekty. Provedeme kompilaci celého našeho projektu.

Přetáhneme ze složky debug těchto projektů spouštěcí soubory na plochu jako zástupce. Spustíme ClientServer, MujServerEven­tListener a nakonec TestServeru. Pokud vše funguje, uvidíte:

Testy serveru

Ve všech projektech můžete ladit, krokovat a provádět běžné činnosti Visual Studia.

Vytváření čítačů pro sledování výkonu

Novou kategorii čítačů pro naši službu vytvoříme v průzkumníku serverů, v aplikaci Visual Studio.

Přihlášeni k našemu PC

Po vyplnění přihlašovací tabulky, pokud nejsme administrator, VS naši aplikaci uloží, automaticky se přihlásí jako administrátor Visual Studia a znovu otevře naši aplikaci.

Připojení k serveru

Pravým tlačítkem myši na čítačích výkonu zadáme novou kategorii a zobrazí se tabulka.

Nový čítač

Tabulku vyplníme podle našich požadavků.

Přidávání komponent PerformanceCounter do služby

Můžeme postupovat buď přetažením komponenty nebo přidávat z panelu nástrojů. Zase nejjednodušší způsob je přetáhnout komponentu z průzkumníka serverů. Tímto způsobem dojde k automatickému nakonfigurování nových instancí:

  • jméno PC (MachineName)
  • název kategorie (CategoryName)
  • vlastnost názvu (CounterName)

Nastavíme performanceCou­nter.ReadOnly = false, v této aplikaci služby nebudeme čítače výkonu číst, ale pouze zapisovat.

Výkonostní čítače, které ukazují celkové hodnoty, zvyšujeme přímo v metodě ListenerThread() třídy MujServer (viz ukázka kódu) . Pro počítání celkového počtu požadavků použijeme metodu performanceCou­nter.Incremen­t() a výpočet odeslaných bajtů lze provést voláním metody performanceCou­nter.Incremen­tBy()

Přidání čítače do služby

Omlouvám se, obrázky jsou z jiné služby a již jsem je nepředělával.

Class Server1 - doplnění kódu

public partial class Server1 : Component
{
        //původní kód
        private byte[] buffer;
        private int bytesPerSec = 0;
        private int requestsPerSec = 0;

        protected void ListenerThread()
        {
                //původní kód
                if (!listener.Pending())
                {
                        Thread.Sleep(500);
                }
                else
                {
                        //původní kód
                        //čítače výkonu
                        this.performanceCounter1.Increment();
                        requestsPerSec++;
                        bytesPerSec += buffer.Length;
                }

         private void Init()
         {
                //přidáme
                this.performanceCounter1.ReadOnly = false;
                this.performanceCounter2.ReadOnly = false;
                this.performanceCounter3.ReadOnly = false;
         }

        private void timer1_Tick(object sender, EventArgs e)
        {
            this.performanceCounter2.RawValue = requestsPerSec;
            this.performanceCounter3.RawValue = bytesPerSec;
            bytesPerSec = 0 ;
            requestsPerSec = 0;
        }
}

Aby vše fungovalo tak jak má, musíme přetáhnout na plochu čítač (Timer1), délka intervalu 1000 mS a trvale spouštěný. Myslím, že tato část nepotřebuje komentář. Potíž může nastat v nevhodně zvoleném typu čítače výkonu, zde doplňuji článkem z CodeProject:

Článek z CodeProject

Řešení není úplné, po restartu nebo odinstalování se z průzkumníka severu ztratí naše aplikace z čítačů výkonu. Pokud opravdu čítače výkonu potřebujete, musíte vytvořit kolekci, v tomto případě MojeService1. Jakým způsobem to provedete je rozebráno v uvedeném článku. Pokládám tento popis za zbytečný, článek by se rozšířil o dva další díly. Čítače výkonu musí být taktéž registrovány v registru.

Budeme pokračovat v dalším dílu.


 

Stáhnout

Staženo 53x (326.73 kB)
Aplikace je včetně zdrojových kódů v jazyce C#

 

  Aktivity (1)

Článek pro vás napsal zpavlu
Avatar
C# a C++

Jak se ti líbí článek?
Ještě nikdo nehodnotil, buď první!


 


Miniatura
Všechny články v sekci
C# - Pro pokročilé

 

 

Komentáře

Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zatím nikdo nevložil komentář - buď první!