Heim Backend-Entwicklung Golang Einen Windows-Dienst in Go schreiben

Einen Windows-Dienst in Go schreiben

Aug 28, 2024 am 06:40 AM

Writing a Windows Service in Go

Inhaltsverzeichnis

  • Einführung
  • Was genau ist ein Windows-„Dienst“?
  • Warum Golang?
  • Einen Windows-Dienst in Go schreiben
  • Installieren und Starten des Dienstes
  • Fazit
  • Vollständiger Code

Einführung

Hallo Entwickler, es ist schon eine Weile her, seit ich etwas Windows-artiges geschrieben habe. Deshalb möchte ich euch heute zeigen, wie man eine Windows-Dienstanwendung in Go schreibt. Ja, Sie haben es richtig gehört, es geht um Sprache. In diesem Tutorial-Blog behandeln wir einige grundlegende Dinge zu Windows-Dienstanwendungen und im späteren Teil führe ich Sie durch einen einfachen Code-Rundgang, bei dem wir Code für einen Windows-Dienst schreiben, der einige Informationen in einer Datei protokolliert. Ohne weitere Umschweife: Fangen wir an...!

Was genau ist ein Windows-„Dienst“?

Eine Windows-Dienstanwendung, auch bekannt als Windows-Dienste, sind kleine Anwendungen, die im Hintergrund ausgeführt werden. Im Gegensatz zu normalen Windows-Anwendungen verfügen sie weder über eine grafische Benutzeroberfläche noch über irgendeine Benutzeroberfläche. Diese Dienstanwendungen werden ausgeführt, wenn der Computer hochfährt. Es läuft unabhängig davon, unter welchem ​​Benutzerkonto es ausgeführt wird. Sein Lebenszyklus (Start, Stopp, Pause, Fortfahren usw.) wird von einem Programm namens Service Control Manager (SCM) gesteuert.

Daraus können wir also verstehen, dass wir unseren Windows-Dienst so schreiben sollten, dass der SCM mit unserem Windows-Dienst interagieren und seinen Lebenszyklus verwalten sollte.

Warum Golang?

Es gibt mehrere Faktoren, die Sie zum Schreiben von Windows-Diensten in Betracht ziehen können.

Parallelität

Das Parallelitätsmodell von Go ermöglicht eine schnellere und ressourceneffiziente Verarbeitung. Mit den Goroutinen von Go können wir Anwendungen schreiben, die Multitasking ohne Blockierung oder Deadlocks ausführen können.

Einfachheit

Traditionell werden Windows-Dienste entweder mit C++ oder C (manchmal C#) geschrieben, was nicht nur zu einem komplexen Code, sondern auch zu einer schlechten DX (Developer Experience) führt. Gos Implementierung der Windows-Dienste ist unkompliziert und jede Codezeile macht Sinn.

Statische Binärdateien

Sie fragen sich vielleicht: „Warum nicht eine noch einfachere Sprache wie Python verwenden?“ Der Grund liegt in der interpretierten Natur von Python. Go kompiliert zu einer statisch verknüpften Einzeldatei-Binärdatei, die für die effiziente Funktion eines Windows-Dienstes unerlässlich ist. Go-Binärdateien erfordern keine Laufzeit/Interpreter. Go-Code kann auch kreuzkompiliert werden.

Zugang auf niedriger Ebene

Obwohl Go eine Garbage-Collected-Sprache ist, bietet es solide Unterstützung für die Interaktion mit Low-Level-Elementen. Wir können problemlos Win32-APIs und allgemeine Systemaufrufe in go aufrufen.

Okay, genug Informationen. Lass uns programmieren...

Einen Windows-Dienst in Go schreiben

Diese Code-Anleitung setzt voraus, dass Sie über Grundkenntnisse der Go-Syntax verfügen. Wenn nicht, wäre A Tour of Go ein guter Ort, um es zu lernen.

  • Als Erstes benennen wir unser Projekt. Ich werde meine als cosmic/my_service bezeichnen. Erstellen Sie eine go.mod-Datei.
PS C:\> go mod init cosmic/my_service
Nach dem Login kopieren
  • Jetzt müssen wir das Paket golang.org/x/sys installieren. Dieses Paket bietet Go-Sprachunterstützung für Windows-bezogene Anwendungen.
PS C:\> go get golang.org/x/sys
Nach dem Login kopieren

Hinweis: Dieses Paket enthält auch OS-Level-Go-Sprachunterstützung für UNIX-basierte Betriebssysteme wie Mac OS und Linux.

  • Erstellen Sie eine main.go-Datei. Die Datei main.go enthält die Hauptfunktion, die als Einstiegspunkt für unsere Go-Anwendung/unseren Go-Dienst fungiert.

  • Um eine Dienstinstanz zu erstellen, müssen wir etwas namens Service Context schreiben, das die Handler-Schnittstelle von golang.org/x/sys/windows/svc implementiert.

Die Schnittstellendefinition sieht also ungefähr so ​​aus

type Handler interface {
    Execute(args []string, r <-chan ChangeRequest, s chan<- Status) (svcSpecificEC bool, exitCode uint32)
}
Nach dem Login kopieren

Die Execute-Funktion wird vom Paketcode beim Start des Dienstes aufgerufen und der Dienst wird beendet, sobald die Ausführung abgeschlossen ist.

Wir lesen Serviceänderungsanfragen vom Nur-Empfangskanal r und handeln entsprechend. Wir sollten unseren Dienst auch mit dem Senden von Signalen an reine Sendekanäle auf dem neuesten Stand halten. Wir können optionale Argumente an den args-Parameter übergeben.

Beim Beenden können wir bei erfolgreicher Ausführung mit dem ExitCode 0 zurückkehren. Dafür können wir auch svcSpecificEC verwenden.

  • Erstellen Sie nun einen Typ namens „myService“, der als unser Servicekontext fungiert.
type myService struct{}
Nach dem Login kopieren
  • Nachdem Sie den Typ myService erstellt haben, fügen Sie ihm die oben erwähnte Execute-Methode hinzu, damit er die Handler-Schnittstelle implementiert.
func (m *myService) Execute(args []string, r <-chan svc.ChangeRequest, status chan<- svc.Status) (bool, uint32) {
    // to be filled
}
Nach dem Login kopieren
  • Nachdem wir die Handler-Schnittstelle erfolgreich implementiert haben, können wir nun mit dem Schreiben der eigentlichen Logik beginnen.

Erstellen Sie eine Konstante mit den Signalen, die unser Service von SCM akzeptieren kann.

const cmdsAccepted = svc.AcceptStop | svc.AcceptShutdown | svc.AcceptPauseAndContinue
Nach dem Login kopieren

Our main goal is the log some data every 30 seconds. So we need to define a thread safe timer for that.

tick := time.Tick(30 * time.Second)
Nach dem Login kopieren

So, we have done all the initialization stuffs. It's time to send START signal to the SCM. we're going to do exactly that,

status <- svc.Status{State: svc.StartPending}
status <- svc.Status{State: svc.Running, Accepts: cmdsAccepted}
Nach dem Login kopieren

Now we're going to write a loop which acts as a mainloop for our application. Handling events in loop makes our application never ending and we can break the loop only when the SCM sends STOP or SHUTDOWN signal.

loop:
    for {
        select {
        case <-tick:
            log.Print("Tick Handled...!")
        case c := <-r:
            switch c.Cmd {
            case svc.Interrogate:
                status <- c.CurrentStatus
            case svc.Stop, svc.Shutdown:
                log.Print("Shutting service...!")
                break loop
            case svc.Pause:
                status <- svc.Status{State: svc.Paused, Accepts: cmdsAccepted}
            case svc.Continue:
                status <- svc.Status{State: svc.Running, Accepts: cmdsAccepted}
            default:
                log.Printf("Unexpected service control request #%d", c)
            }
        }
    }
Nach dem Login kopieren

Here we used a select statement to receive signals from channels. In first case, we handle the Timer's tick signal. This case receives signal every 30 seconds, as we declared before. We log a string "Tick Handled...!" in this case.

Secondly, we handle the signals from SCM via the receive-only r channel. So, we assign the value of the signal from r to a variable c and using a switch statement, we can handle all the lifecycle event/signals of our service. We can see about each lifecycle below,

  1. svc.Interrogate - Signal requested by SCM on a timely fashion to check the current status of the service.
  2. svc.Stop and svc.Shutdown - Signal sent by SCM when our service needs to be stopped or Shut Down.
  3. svc.Pause - Signal sent by SCM to pause the service execution without shutting it down.
  4. svc.Continue - Signal sent by SCM to resume the paused execution state of the service.

So, when on receiving either svc.Stop or svc.Shutdown signal, we break the loop. It is to be noted that we need to send STOP signal to the SCM to let the SCM know that our service is stopping.

status <- svc.Status{State: svc.StopPending}
return false, 1
Nach dem Login kopieren
  • Now we write a function called runService where we enable our service to run either in Debug mode or in Service Control Mode.

Note: It's super hard to debug Windows Service Applications when running on Service Control Mode. That's why we are writing an additional Debug mode.

func runService(name string, isDebug bool) {
    if isDebug {
        err := debug.Run(name, &myService{})
        if err != nil {
            log.Fatalln("Error running service in debug mode.")
        }
    } else {
        err := svc.Run(name, &myService{})
        if err != nil {
            log.Fatalln("Error running service in debug mode.")
        }
    }
}
Nach dem Login kopieren
  • Finally we can call the runService function in our main function.
func main() {

    f, err := os.OpenFile("debug.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
    if err != nil {
        log.Fatalln(fmt.Errorf("error opening file: %v", err))
    }
    defer f.Close()

    log.SetOutput(f)
    runService("myservice", false) //change to true to run in debug mode
}
Nach dem Login kopieren

Note: We are logging the logs to a log file. In advanced scenarios, we log our logs to Windows Event Logger. (phew, that sounds like a tongue twister ?)

  • Now run go build to create a binary '.exe'. Optionally, we can optimize and reduce the binary file size by using the following command,
PS C:\> go build -ldflags "-s -w"
Nach dem Login kopieren

Installing and Starting the Service

For installing, deleting, starting and stopping our service, we use an inbuilt tool called sc.exe

To install our service, run the following command in powershell as Administrator,

PS C:\> sc.exe create MyService <path to your service_app.exe>
Nach dem Login kopieren

To start our service, run the following command,

PS C:\> sc.exe start MyService
Nach dem Login kopieren

To delete our service, run the following command,

PS C:\> sc.exe delete MyService
Nach dem Login kopieren

You can explore more commands, just type sc.exe without any arguments to see the available commands.

Conclusion

As we can see, implementing Windows Services in go is straightforward and requires minimal implementation. You can write your own windows services which acts as a web server and more. Thanks for reading and don't forget to drop a ❤️.

Complete Code

Here is the complete code for your reference.

// file: main.go

package main

import (
    "fmt"
    "golang.org/x/sys/windows/svc"
    "golang.org/x/sys/windows/svc/debug"
    "log"
    "os"
    "time"
)

type myService struct{}

func (m *myService) Execute(args []string, r <-chan svc.ChangeRequest, status chan<- svc.Status) (bool, uint32) {

    const cmdsAccepted = svc.AcceptStop | svc.AcceptShutdown | svc.AcceptPauseAndContinue
    tick := time.Tick(5 * time.Second)

    status <- svc.Status{State: svc.StartPending}

    status <- svc.Status{State: svc.Running, Accepts: cmdsAccepted}

loop:
    for {
        select {
        case <-tick:
            log.Print("Tick Handled...!")
        case c := <-r:
            switch c.Cmd {
            case svc.Interrogate:
                status <- c.CurrentStatus
            case svc.Stop, svc.Shutdown:
                log.Print("Shutting service...!")
                break loop
            case svc.Pause:
                status <- svc.Status{State: svc.Paused, Accepts: cmdsAccepted}
            case svc.Continue:
                status <- svc.Status{State: svc.Running, Accepts: cmdsAccepted}
            default:
                log.Printf("Unexpected service control request #%d", c)
            }
        }
    }

    status <- svc.Status{State: svc.StopPending}
    return false, 1
}

func runService(name string, isDebug bool) {
    if isDebug {
        err := debug.Run(name, &myService{})
        if err != nil {
            log.Fatalln("Error running service in debug mode.")
        }
    } else {
        err := svc.Run(name, &myService{})
        if err != nil {
            log.Fatalln("Error running service in debug mode.")
        }
    }
}

func main() {

    f, err := os.OpenFile("E:/awesomeProject/debug.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
    if err != nil {
        log.Fatalln(fmt.Errorf("error opening file: %v", err))
    }
    defer f.Close()

    log.SetOutput(f)
    runService("myservice", false)
}
Nach dem Login kopieren

Das obige ist der detaillierte Inhalt vonEinen Windows-Dienst in Go schreiben. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn

Heiße KI -Werkzeuge

Undresser.AI Undress

Undresser.AI Undress

KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover

AI Clothes Remover

Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool

Undress AI Tool

Ausziehbilder kostenlos

Clothoff.io

Clothoff.io

KI-Kleiderentferner

Video Face Swap

Video Face Swap

Tauschen Sie Gesichter in jedem Video mühelos mit unserem völlig kostenlosen KI-Gesichtstausch-Tool aus!

Heißer Artikel

<🎜>: Bubble Gum Simulator Infinity - So erhalten und verwenden Sie Royal Keys
3 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
Nordhold: Fusionssystem, erklärt
3 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
Mandragora: Flüstern des Hexenbaum
3 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌

Heiße Werkzeuge

Notepad++7.3.1

Notepad++7.3.1

Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version

SublimeText3 chinesische Version

Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1

Senden Sie Studio 13.0.1

Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6

Dreamweaver CS6

Visuelle Webentwicklungstools

SublimeText3 Mac-Version

SublimeText3 Mac-Version

Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Heiße Themen

Java-Tutorial
1666
14
PHP-Tutorial
1273
29
C#-Tutorial
1252
24
Golang gegen Python: Leistung und Skalierbarkeit Golang gegen Python: Leistung und Skalierbarkeit Apr 19, 2025 am 12:18 AM

Golang ist in Bezug auf Leistung und Skalierbarkeit besser als Python. 1) Golangs Kompilierungseigenschaften und effizientes Parallelitätsmodell machen es in hohen Parallelitätsszenarien gut ab. 2) Python wird als interpretierte Sprache langsam ausgeführt, kann aber die Leistung durch Tools wie Cython optimieren.

Golang und C: Parallelität gegen Rohgeschwindigkeit Golang und C: Parallelität gegen Rohgeschwindigkeit Apr 21, 2025 am 12:16 AM

Golang ist in Gleichzeitigkeit besser als C, während C bei Rohgeschwindigkeit besser als Golang ist. 1) Golang erreicht durch Goroutine und Kanal eine effiziente Parallelität, die zum Umgang mit einer großen Anzahl von gleichzeitigen Aufgaben geeignet ist. 2) C über Compiler -Optimierung und Standardbibliothek bietet es eine hohe Leistung in der Nähe der Hardware, die für Anwendungen geeignet ist, die eine extreme Optimierung erfordern.

Golang gegen C: Leistung und Geschwindigkeitsvergleich Golang gegen C: Leistung und Geschwindigkeitsvergleich Apr 21, 2025 am 12:13 AM

Golang ist für schnelle Entwicklung und gleichzeitige Szenarien geeignet, und C ist für Szenarien geeignet, in denen extreme Leistung und Kontrolle auf niedriger Ebene erforderlich sind. 1) Golang verbessert die Leistung durch Müllsammlung und Parallelitätsmechanismen und eignet sich für die Entwicklung von Webdiensten mit hoher Konsequenz. 2) C erreicht die endgültige Leistung durch das manuelle Speicherverwaltung und die Compiler -Optimierung und eignet sich für eingebettete Systementwicklung.

Golangs Auswirkungen: Geschwindigkeit, Effizienz und Einfachheit Golangs Auswirkungen: Geschwindigkeit, Effizienz und Einfachheit Apr 14, 2025 am 12:11 AM

GoimpactsDevelopmentPositivyThroughSpeed, Effizienz und DiasMlitication.1) Geschwindigkeit: Gocompilesquickandrunseffiction, idealforlargeProjects

Erste Schritte mit Go: Ein Anfängerführer Erste Schritte mit Go: Ein Anfängerführer Apr 26, 2025 am 12:21 AM

GoisidealforBeginersandSuitableforCloudandNetWorkServicesDuetoitsSimplicity, Effizienz und Konsumfeaturen.1) InstallgoFromTheofficialwebSiteAnDverifyWith'goversion'.2) CreateAneDrunyourFirstProgramwith'gorunhello.go.go.go.

Golang gegen Python: Schlüsselunterschiede und Ähnlichkeiten Golang gegen Python: Schlüsselunterschiede und Ähnlichkeiten Apr 17, 2025 am 12:15 AM

Golang und Python haben jeweils ihre eigenen Vorteile: Golang ist für hohe Leistung und gleichzeitige Programmierung geeignet, während Python für Datenwissenschaft und Webentwicklung geeignet ist. Golang ist bekannt für sein Parallelitätsmodell und seine effiziente Leistung, während Python für sein Ökosystem für die kurze Syntax und sein reiches Bibliothek bekannt ist.

C und Golang: Wenn die Leistung von entscheidender Bedeutung ist C und Golang: Wenn die Leistung von entscheidender Bedeutung ist Apr 13, 2025 am 12:11 AM

C eignet sich besser für Szenarien, in denen eine direkte Kontrolle der Hardware -Ressourcen und hohe Leistungsoptimierung erforderlich ist, während Golang besser für Szenarien geeignet ist, in denen eine schnelle Entwicklung und eine hohe Parallelitätsverarbeitung erforderlich sind. 1.Cs Vorteil liegt in den nahezu Hardware-Eigenschaften und hohen Optimierungsfunktionen, die für leistungsstarke Bedürfnisse wie die Spieleentwicklung geeignet sind. 2. Golangs Vorteil liegt in seiner präzisen Syntax und der natürlichen Unterstützung, die für die Entwicklung einer hohen Parallelitätsdienste geeignet ist.

Golang und C: Die Kompromisse bei der Leistung Golang und C: Die Kompromisse bei der Leistung Apr 17, 2025 am 12:18 AM

Die Leistungsunterschiede zwischen Golang und C spiegeln sich hauptsächlich in der Speicherverwaltung, der Kompilierungsoptimierung und der Laufzeiteffizienz wider. 1) Golangs Müllsammlung Mechanismus ist praktisch, kann jedoch die Leistung beeinflussen.

See all articles