Maison >développement back-end >Golang >Comment arrêter progressivement un serveur d'écoute Go ?

Comment arrêter progressivement un serveur d'écoute Go ?

Patricia Arquette
Patricia Arquetteoriginal
2024-12-24 03:15:12619parcourir

How to Gracefully Shut Down a Go Listening Server?

Comment arrêter gracieusement un serveur d'écoute dans Go

Dans Go, la fonction Listen.Accept bloque l'exécution, ce qui rend difficile la résiliation d'un serveur d'écoute. serveur d'écoute avec élégance. Pour déterminer quand arrêter le serveur, une approche consiste à fermer le socket d’écoute et à détecter l’erreur spécifique indiquant une connexion réseau fermée. Cependant, cette erreur n'est pas exportée par le package net, ce qui oblige les développeurs à recourir à une gestion des erreurs délicate.

Heureusement, il existe une solution plus élégante. En utilisant un canal terminé, vous pouvez signaler au serveur de s'arrêter avant de fermer la connexion. Voici comment cela peut être implémenté avec un exemple de code :

package main

import (
    "io"
    "log"
    "net"
    "sync"
    "time"
)

// Echo server struct
type EchoServer struct {
    listen net.Listener
    done   sync.WaitGroup
}

// Respond to incoming connection
//
// Write the address connected to then echo
func (es *EchoServer) respond(remote *net.TCPConn) {
    defer remote.Close()
    _, err := io.Copy(remote, remote)
    if err != nil {
        log.Printf("Error: %s", err)
    }
}

// Listen for incoming connections
func (es *EchoServer) serve() {
    for {
        conn, err := es.listen.Accept()
        if err != nil {
            select {
            case <-es.done:
                // Server has been stopped, so we can exit without showing the error.
            default:
                log.Printf("Accept failed: %v", err)
            }
            return
        }
        es.done.Add(1) // Increment the waitgroup for each incoming connection
        go func() {
            es.respond(conn.(*net.TCPConn))
            es.done.Done() // Decrement the waitgroup when done handling the connection
        }()
    }
}

// Stop the server by closing the listening listen
func (es *EchoServer) stop() {
    es.done.Wait() // Wait for all outstanding connections to finish handling
    es.listen.Close() // Now it the Accept will have an error above
}

// Make a new echo server
func NewEchoServer(address string) *EchoServer {
    listen, err := net.Listen("tcp", address)
    if err != nil {
        log.Fatalf("Failed to open listening socket: %s", err)
    }
    es := &amp;EchoServer{
        listen: listen,
    }
    es.done.Add(1)
    go es.serve()
    return es
}

// Main
func main() {
    log.Println("Starting echo server")
    es := NewEchoServer("127.0.0.1:18081")
    // Run the server for 1 second
    time.Sleep(1 * time.Second)
    // Close the server
    log.Println("Stopping echo server")
    es.stop()
}

Dans ce code, la fonction serve termine gracieusement le serveur en retournant lorsqu'une valeur est reçue sur le canal terminé. La fonction principale montre comment démarrer le serveur, attendre les connexions, puis y mettre fin correctement. En utilisant un canal terminé, la gestion des erreurs est clairement séparée de la logique d'arrêt, ce qui donne un serveur plus maintenable et sans erreur.

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