如何在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 := &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中文網其他相關文章!