#go #ssl #tcp
#Вперед #ssl #tcp
Вопрос:
Я хочу увеличить период ожидания моего TCP-соединения как для HTTP, так и для HTTPS-запросов.
Для HTTP-запросов это можно сделать следующим образом:
package main
import (
"fmt"
"io"
"log"
"net"
"net/http"
"time"
)
func main() {
server := amp;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())
}
Для запросов HTTPS это невозможно сделать через, server.ConnState
потому что net.Conn
то, что будет передано внутри функции, является *tls.Conn
. Это соединение не предоставляет такую функцию, как SetKeepAlivePeriod
или предоставляет доступ к базовой *net.TCPConn
.
func main() {
server := amp;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"))
}
Как я могу установить период ожидания для соединений tls?
Ответ №1:
Есть (как минимум) два способа сделать это:
Используйте сеть.ListenConfig:
У net.ListenConfig
объекта есть KeepAlive time.Duration
поле. Если значение не равно нулю, оно будет использоваться для настройки режима сохранения при принятых соединениях (например: для TCP в posix).
Вы можете передать прослушиватель ServeTLS
:
server := amp;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"))
Как уже упоминалось, для принятых TCP-соединений автоматически будет включена поддержка и периоду будет присвоено указанное значение.
Используйте обратный вызов tls.Config:
Вы можете получить доступ к net.Conn
базовому tls.Conn
, установив tls.Config GetConfigForClient
или GetCertificate
обратный вызов.
Не имеет значения, какой из них вы используете, пока вы возвращаетесь nil
, чтобы заставить код TLS вернуться к поведению по умолчанию. Важной частью является получение доступа к tls.ClientHelloInfo, который имеет .Conn
поле, указывающее на базовое соединение. Это приведет к 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 := amp;tls.Config{
...
GetConfigForClient: setTCPKeepAlive,
...
}
server := amp;http.Server{
Addr: ":8080",
TLSConfig: tlsConfig,
}
server.ListenAndServeTLS("../example.crt", "../example.key")
Комментарии:
1. Установка
KeepAlive
вклnet.ListenConfig
кажется лучшим решением, никаких утверждений типа не требуется, и это просто работает. Спасибо!2. Я конкретизировал
net.ListenConfig
метод и перечислил его первым, поскольку он намного проще.