首頁 >後端開發 >Golang >golang http 關閉連接

golang http 關閉連接

WBOY
WBOY原創
2023-05-13 10:03:361665瀏覽

在使用 Golang 進行 HTTP 程式設計時,我們需要經常考慮如何關閉連線。關閉連線可以有效避免資源浪費、提升效能,減少網路問題帶來不必要的麻煩。本文將詳細介紹 Golang 中如何關閉 HTTP 連接,並解析其中的一些細節問題。

一、HTTP 連線的關閉方式

Go 語言中的 HTTP 用戶端和服務端實作了一系列的底層處理來管理 HTTP 連線。這些底層處理通常不會向使用者暴露出來,而是被 HTTP 用戶端和服務端隱藏在內部實作中。那麼在 HTTP 用戶端和服務端中,如何關閉連線呢?

  1. HTTP 用戶端

在HTTP 用戶端中,我們有幾種方式可以關閉連線:

  • 使用defer 關鍵字來手動關閉連線:客戶端呼叫介面後,一般會自動關閉連線。但如果當前客戶端需要多次請求接口,可以考慮手動控制連接關閉,使用defer延遲關閉連接,代碼如下:
package main
import (
    "net/http"
    "io/ioutil"
    "fmt"
    "log"
)
func main() {
    client := &http.Client{}
    req, err := http.NewRequest("GET", "http://www.baidu.com", nil)
    if err != nil {
        log.Fatal(err)
    }
    defer client.CloseIdleConnections() // 当函数返回时释放连接
    resp, err := client.Do(req)
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close() // 当函数返回时关闭body
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(string(body)[:50])
}
  • 使用Transport 類別的MaxIdleConns 或MaxIdleConnsPerHost 來控制連接池中的連線上限:Go 語言的http.Transport 包含了預設的連線池,用於管理HTTP 連線。我們可以使用其 MaxIdleConns 和 MaxIdleConnsPerHost 兩個參數來指定最大空閒連線數和最大空閒主機連線數。當達到這個空閒數時,Transport 會自動關閉多餘的連線。程式碼如下:
package main
import (
    "net/http"
    "io/ioutil"
    "fmt"
    "log"
)
func main() {
    transport := &http.Transport{
        MaxIdleConns:          10, // 最大空闲连接数
        MaxIdleConnsPerHost:   3,  // 每个域名地址最大空闲连接数
    }
    client := &http.Client{Transport: transport}
    req, err := http.NewRequest("GET", "http://www.baidu.com", nil)
    if err != nil {
        log.Fatal(err)
    }
    resp, err := client.Do(req)
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(string(body)[:50])
}
  1. HTTP 服務端

在 HTTP 服務端中,連線管理通常由伺服器實作自動管理。我們只需要建立伺服器並在不需要使用連接時關閉它。通常情況下,伺服器在處理完一個請求後會自動關閉連線。但有幾種情況比較特殊,需要我們手動控制連線的關閉:

  • 在一個HTTP 處理器中使用conn.Close() 關閉連線:在處理器處理HTTP 要求時,如果處理器需要關閉連接,則可以使用conn.Close() 方法關閉連接。程式碼如下:
package main
import (
    "fmt"
    "net/http"
)
func handler(w http.ResponseWriter, req *http.Request) {
    // 需要关闭连接时,使用conn.Close()
    conn, _, _ := w.(http.Hijacker).Hijack()
    conn.Close()
}
func main() {
    http.HandleFunc("/", handler)
    http.ListenAndServe(":8080", nil)
}
  • 使用 Keep-Alive:在使用 Keep-Alive 時,連線的生命週期由伺服器管理。伺服器可以定義一個 keep-alive 時間,來控制連線在閒置時間後應關閉。這個時間一般在 HTTP header 中設定。程式碼如下:
package main
import (
    "log"
    "net/http"
)
func handler(w http.ResponseWriter, req *http.Request) {
    w.Header().Set("Connection", "keep-alive") // 定义keep-alive时间
    w.Write([]byte("hello world"))
}
func main() {
    http.HandleFunc("/", handler)
    log.Fatal(http.ListenAndServe(":8080", nil))
}

二、HTTP 連線的回收機制

當連線使用完畢後,我們需要為連接回收資源,防止資源外洩、效能下降等問題。 HTTP 連線資源的回收機制通常需要考慮以下問題:

  • HTTP 長連線的最大存在時間:在連線空閒一段時間後,伺服器會立刻回收這個連線。這個時間可以由伺服器決定,在建立伺服器物件時設定連線逾時時間即可。
  • HTTP 連線的最大連線數:在一段時間內,允許連線在連線池中的最大數量。當連接池中出現超出連接池大小的連接時,它們將自動關閉。
  • HTTP 連線的複用機制:連線複用是指在同一時間多個請求共用一個連線。這可以減少長時間等待狀態下不必要的資源佔用。但是需要注意的是,如果連線逾時時間較短,可能會導致一次具有網路瞬時性波動的請求失敗,從而影響系統的穩定性。

三、HTTP 連接池的管理

在大型高並發的系統中,我們需要使用連接池來管理 HTTP 連接,以提升系統的效能和穩定性。當呼叫 HTTP 請求時,連線池可以提供一個空閒的網路連線從而避免了頻繁地建立銷毀連線的開銷。連接池通常以常規佇列來管理,以確保最先進入佇列的元素最先被使用,即 FIFO 佇列。以下是使用 Go 語言實作 HTTP 連線池的程式碼:

package main
import (
    "fmt"
    "log"
    "net/http"
    "sync"
    "time"
)
type MyHttpClient struct {
    client    *http.Client     // http客户端对象
    Transport *http.Transport  // transport对象,用于管理http连接池
}
var once sync.Once
var myClient *MyHttpClient
func GetMyHttpClient() *MyHttpClient {
    once.Do(func() {
        myClient = &MyHttpClient{
            Transport: &http.Transport{
                Dial: func(network, addr string) (net.Conn, error) {
                    conn, err := net.DialTimeout(network, addr, 10*time.Second)
                    if err != nil {
                        return nil, err
                    }
                    return conn, nil
                },
                MaxIdleConns:          100,               // 连接池中最多拥有的连接数
                MaxIdleConnsPerHost:   2,                 // 每个域名最多拥有的连接数
                IdleConnTimeout:       60 * time.Second,  // 连接在闲置多久后被关闭
                TLSHandshakeTimeout:   10 * time.Second,  // TLS握手时限
                ExpectContinueTimeout: 1 * time.Second,   // 100-continue超时时限
            },
            client: &http.Client{},
        }
    })
    return myClient
}
func main() {
    client := GetMyHttpClient().client
    req, err := http.NewRequest("GET", "http://www.baidu.com", nil)
    if err != nil {
        log.Fatal(err)
    }
    defer client.CloseIdleConnections()
    resp, err := client.Do(req)
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(string(body)[:50])
}

四、總結

HTTP 連線的控制和回收是一個關鍵的效能最佳化點。在 Golang 中,我們可以透過手動控制、使用 Transport 類別的參數設定、使用連接池等方式來管理 HTTP 連接,以提升系統的效能和穩定性。除此之外,我們還需要考慮到連接回收機制、HTTP 連接池的管理等問題,以做好系統的維護與最佳化。

以上是golang http 關閉連接的詳細內容。更多資訊請關注PHP中文網其他相關文章!

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