Maison  >  Article  >  développement back-end  >  Golang implémente un processus démon

Golang implémente un processus démon

王林
王林original
2023-05-12 21:15:061927parcourir

Avec le développement rapide d'Internet, les applications exécutées sur le serveur deviennent de plus en plus importantes. Cependant, les serveurs doivent souvent exécuter certains processus pendant de longues périodes, ce qui nécessite un processus spécial pour les surveiller et garantir qu'ils sont toujours en cours d'exécution. Ce processus spécial est appelé démon ou démon. Dans cet article, nous verrons comment implémenter un démon à l'aide de Golang.

Qu'est-ce qu'un démon ?

Un démon est un processus qui s'exécute en arrière-plan et reste en cours d'exécution. En règle générale, un démon est un programme de type service qui n'interagit pas avec l'utilisateur mais s'exécute au démarrage de la machine et n'est arrêté qu'à l'arrêt de la machine. Les démons surveillent généralement des services ou des processus spécifiques et les redémarrent automatiquement s'ils cessent de fonctionner.

Pourquoi avons-nous besoin d'un démon ?

Le rôle du démon est de maintenir l'application en marche, même si une erreur dans l'application elle-même entraîne son arrêt. Lorsque nous devons exécuter certains services sur le serveur à tout moment, en particulier certains services qui doivent fonctionner pendant une longue période, ces services peuvent rencontrer diverses erreurs au cours du processus en cours, et ces erreurs peuvent entraîner l'arrêt du service. À l'heure actuelle, nous avons besoin d'un mécanisme pour surveiller automatiquement l'état d'exécution du service et le redémarrer automatiquement lorsque le service cesse de fonctionner.

Comment implémenter un processus démon ?

Dans l'environnement Linux, nous pouvons utiliser systemd ou init.d pour implémenter le processus démon. Mais dans cet article, nous verrons comment implémenter vous-même un processus démon à l'aide de Golang.

Tout d’abord, nous devons configurer le processus démon dans la fonction main() du programme. Voici un exemple de code pour configurer le démon :

package main

import (
    "fmt"
    "os"
    "os/exec"
    "syscall"
)

func main() {
    cmd := exec.Command(os.Args[0], os.Args[1:]...)
    cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true}

    err := cmd.Start()
    if err != nil {
        fmt.Println("Start error:", err)
        os.Exit(1)
    }

    fmt.Println("Process pid:", cmd.Process.Pid)
    os.Exit(0)
}

Avant de configurer le démon, nous devons appeler os.Args pour obtenir tous les paramètres de l'application, et utiliser os /exec code> pour l'exécuter. Lors de l'exécution de la commande, nous devons définir la valeur <code>Setsid sur true pour garantir la création d'une nouvelle session. Cela fait de l'application le premier processus du nouveau groupe de processus et de la nouvelle session. os.Args获得应用程序的所有参数,并使用os/exec模块的其中一个命令来运行它。在运行命令时,我们需要设置Setsid值为true,以确保创建新的会话。这会使应用程序成为新的进程组和新会话的首进程。

一旦我们设置了守护进程,我们需要定义如何处理操作系统的信号。以下是一个捕获操作系统信号的样例代码:

package main

import (
    "fmt"
    "os"
    "os/signal"
    "syscall"
)

func main() {
    // daemon code here...

    signalCh := make(chan os.Signal, 1)
    signal.Notify(signalCh, syscall.SIGTERM)
    signal.Notify(signalCh, syscall.SIGQUIT)
    signal.Notify(signalCh, syscall.SIGINT)

    select {
    case signal := <-signalCh:
        fmt.Printf("Received signal: %s
", signal)
    }
}

在这个例子中,我们使用信号来通知我们何时关闭守护进程。我们使用OS包的make()函数创建一个signalCh通道来接收信号,然后使用signal.Notify()向通道注册三个信号,分别是SIGTERM,SIGQUIT和SIGINT。这些信号是我们需要关注的信号,当守护进程收到它们时,它会终止当前进程。

为了确保守护进程达到我们的期望,我们还需要几个步骤。首先,守护进程需要改变工作目录并刷新文件描述符。以下是一个样例代码:

package main

import (
    "fmt"
    "os"
    "os/exec"
    "syscall"
)

func main() {
    if os.Getppid() != 1 {
        cmd := exec.Command(os.Args[0], os.Args[1:]...)
        cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true}

        err := cmd.Start()
        if err != nil {
            fmt.Println("Start error:", err)
            os.Exit(1)
        }

        fmt.Println("Process pid:", cmd.Process.Pid)
        os.Exit(0)
    }

    os.Chdir("/")
    syscall.Umask(0)

    file, err := os.OpenFile("/dev/null", os.O_RDWR, 0)
    if err != nil {
        fmt.Println("file open error:", err)
        os.Exit(1)
    }

    syscall.Dup2(int(file.Fd()), int(os.Stdin.Fd()))
    syscall.Dup2(int(file.Fd()), int(os.Stdout.Fd()))
    syscall.Dup2(int(file.Fd()), int(os.Stderr.Fd()))
    file.Close()

    // daemon code here...
}

在这个样例代码中,我们首先检查当前守护进程是否在init进程下运行。如果不是,则创建新的守护进程。如果是,则守护进程成为了新创建的会话的首进程。随后,守护进程需要改变工作目录并刷新文件描述符。通过我们使用os.Chdir()函数将工作目录更改为根目录,使用syscall.Umask()设置默认的文件权限,然后使用os.OpenFile()函数打开 /dev/null 文件作为新的标准输入、输出和错误输出,并使用syscall.Dup2()

Une fois le démon configuré, nous devons définir comment gérer les signaux du système d'exploitation. Voici un exemple de code qui capture les signaux du système d'exploitation :

// daemon code here...

Dans cet exemple, nous utilisons des signaux pour nous avertir quand arrêter le démon. Nous utilisons la fonction make() du package OS pour créer un canal signalCh pour recevoir le signal, puis utilisons signal.Notify() pour enregistrer trois Les signaux sont SIGTERM, SIGQUIT et SIGINT. Ces signaux sont ceux auxquels nous devons prêter attention, et lorsque le démon les reçoit, il met fin au processus en cours.

Pour nous assurer que le démon répond à nos attentes, nous avons besoin de quelques étapes supplémentaires. Tout d’abord, le démon doit modifier le répertoire de travail et vider les descripteurs de fichiers. Voici un exemple de code :
    rrreee
  • Dans cet exemple de code, nous vérifions d'abord si le démon actuel s'exécute sous le processus init. Sinon, créez un nouveau démon. Si tel est le cas, le démon devient le premier processus de la session nouvellement créée. Par la suite, le démon doit modifier le répertoire de travail et actualiser les descripteurs de fichiers. En utilisant la fonction os.Chdir(), nous changeons le répertoire de travail en répertoire racine, utilisons syscall.Umask() pour définir les autorisations de fichier par défaut, puis utilisons os. La fonction OpenFile() ouvre le fichier /dev/null en tant que nouvelle entrée, sortie et sortie d'erreur standard et copie tous les descripteurs de fichiers dans /dev/ à l'aide de syscall.Dup2()<.> fichier nul de fonction. </.>
  • Enfin, après avoir vidé le descripteur de fichier, nous mettons tout le code lié au démon à l'emplacement ci-dessous.
  • rrreee
  • Avantages du démon Golang

Golang est très simple à gérer et convient aux débutants

Golang a une bonne gestion de la concurrence et de la mémoire, ce qui peut rendre les démons plus stables sous une charge élevée ; plates-formes, vous pouvez donc développer un démon une seule fois et l'exécuter sur plusieurs plates-formes.

🎜🎜Résumé🎜🎜Dans cet article, nous avons vu comment créer un démon en utilisant Golang. En utilisant les appels système et la gestion des signaux, le démon Golang peut facilement garantir que l'application reste en cours d'exécution et peut facilement surveiller et démarrer certains services de longue durée. De plus, les démons écrits en Golang présentent les avantages d'une gestion multiplateforme, puissante de la mémoire et de performances de concurrence élevées, et peuvent être utilisés pour développer diverses applications. 🎜

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn