Cách đặt SetKeepAlivePeriod trên * tls.Conn

Aug 31 2020

Tôi muốn tăng thời gian duy trì kết nối TCP của mình cho cả yêu cầu HTTP và HTTPS.

Đối với các yêu cầu HTTP, điều này có thể được thực hiện như sau:

package main

import (
    "fmt"
    "io"
    "log"
    "net"
    "net/http"
    "time"
)

func main() {
    server := &http.Server{Addr: ":8080", Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        io.WriteString(w, "Hello, World!")
    })}

    server.ConnState = func(conn net.Conn, state http.ConnState) {
        if state == http.StateNew {
            if err := conn.(*net.TCPConn).SetKeepAlivePeriod(1000 * time.Second); err != nil {
                fmt.Println("Could not set keep alive period", err)
            } else {
                fmt.Println("update keep alive period")
            }
        }
    }

    log.Fatal(server.ListenAndServe())
}

Đối với các yêu cầu HTTPS, điều này không thể được thực hiện thông qua server.ConnStatebởi vì net.Conncái sẽ được chuyển vào bên trong hàm là a *tls.Conn. Kết nối này không hiển thị một chức năng như SetKeepAlivePeriodhoặc cấp quyền truy cập vào cơ sở *net.TCPConn.

func main() {
    server := &http.Server{Addr: ":8080", Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        io.WriteString(w, "Hello, World!")
    })}

    server.ConnState = func(conn net.Conn, state http.ConnState) {
        if state == http.StateNew {
            tlsConn := conn.(*tls.Conn)
            // how to set SetKeepAlivePeriod
        }
    }

    log.Fatal(server.ListenAndServeTLS("../example.crt", "../example.key"))
}

Làm cách nào tôi có thể đặt khoảng thời gian duy trì hoạt động cho các kết nối tls?

Trả lời

1 Marc Aug 31 2020 at 19:46

Có (ít nhất) hai cách để làm điều đó:

Sử dụng mạng.ListenConfig :

Đối net.ListenConfigtượng có một KeepAlive time.Durationtrường. Khi khác 0, điều này sẽ được sử dụng để đặt tính năng duy trì trên các kết nối được chấp nhận (ví dụ: cho TCP trên posix ).

Bạn có thể chuyển người nghe đến ServeTLS:

server := &http.Server{...}

lc := net.ListenConfig{KeepAlive: 1000 * time.Second}
ln, err := lc.Listen(context.Background(), "tcp", ":8080")
if err != nil {
  panic(err)
}
defer ln.Close()

log.Fatal(server.ServeTLS(ln, "../example.crt", "../example.key"))

Như đã đề cập, các kết nối TCP được chấp nhận sẽ tự động được kích hoạt giữ nguyên và khoảng thời gian được đặt thành giá trị được chỉ định.

Sử dụng một cuộc gọi lại tls.Config :

Bạn có thể truy cập phần net.Connbên dưới tls.Connbằng cách thiết lập tls.Config GetConfigForClient hoặc GetCertificategọi lại.

Không quan trọng bạn đang sử dụng cái nào miễn là bạn quay lại nillàm cho mã TLS trở lại hành vi mặc định. Phần quan trọng là truy cập vào tls.ClientHelloInfo có một .Conntrường trỏ đến kết nối cơ bản. Điều này sẽ net.TCPConn.

setTCPKeepAlive := func(clientHello *tls.ClientHelloInfo) (*tls.Config, error) {
  // Check that the underlying connection really is TCP.
  if tcpConn, ok := clientHello.Conn.(*net.TCPConn); ok {
    if err := tcpConn.SetKeepAlivePeriod(1000 * time.Second); err != nil {
      fmt.Println("Could not set keep alive period", err)
    } else {
      fmt.Println("update keep alive period")
    }
  } else {
    fmt.Println("TLS over non-TCP connection")
  }

  // Make sure to return nil, nil to let the caller fall back on the default behavior.
  return nil, nil
}

tlsConfig := &tls.Config{
    ...
    GetConfigForClient: setTCPKeepAlive,
    ...
}

server := &http.Server{
    Addr:      ":8080",
    TLSConfig: tlsConfig,
}

server.ListenAndServeTLS("../example.crt", "../example.key")