首頁 >後端開發 >Golang >如何優雅地關閉Go監聽伺服器?

如何優雅地關閉Go監聽伺服器?

Patricia Arquette
Patricia Arquette原創
2024-12-24 03:15:12622瀏覽

How to Gracefully Shut Down a Go Listening Server?

如何在Go 中優雅地停止監聽伺服器

在Go 中,listen.Accept 函數會阻塞執行,這使得終止監聽伺服器變得困難。優雅地監聽伺服器。要確定何時終止伺服器,一種方法是關閉偵聽套接字並偵測指示關閉的網路連線的特定錯誤。然而,這個錯誤並沒有被 net 套件匯出,導致開發者只能求助於尷尬的錯誤處理。

幸運的是,有一個更優雅的解決方案。透過利用完成通道,您可以在關閉連線之前向伺服器發出停止訊號。以下是如何使用範例程式碼實現它:

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

在此程式碼中,serve 函數透過在完成通道上收到值時返回來優雅地終止伺服器。 main 函數示範如何啟動伺服器、等待連接,然後正常終止它。透過利用完成通道,錯誤處理與關閉邏輯完全分離,從而形成更易於維護且無錯誤的伺服器。

以上是如何優雅地關閉Go監聽伺服器?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn