Heim > Artikel > Backend-Entwicklung > Wie greife ich auf den zugrunde liegenden Socket einer Netz-/http-Antwort zu?
Bei der Arbeit mit HTTP-Verbindungen in Go kann es Szenarios geben, in denen Entwickler auf das zugrunde liegende Netzwerk zugreifen müssen Buchse. Das net/http-Paket bietet eine umfassende Möglichkeit, HTTP-Anfragen und -Antworten zu verarbeiten, stellt den zugrunde liegenden Socket jedoch nicht direkt zur Verfügung. So rufen Sie den Socket in einem Go-Programm ab.
Mit der Veröffentlichung von Go 1.13 führte das Paket net/http die Möglichkeit zum Speichern von ein net.Conn im Anforderungskontext. Dies bietet eine bequeme und saubere Möglichkeit, auf den Socket zuzugreifen:
<code class="go">package main import ( "context" "net/http" "net" "log" ) type contextKey struct { key string } var ConnContextKey = &contextKey{"http-conn"} func SaveConnInContext(ctx context.Context, c net.Conn) (context.Context) { return context.WithValue(ctx, ConnContextKey, c) } func GetConn(r *http.Request) (net.Conn) { return r.Context().Value(ConnContextKey).(net.Conn) } func main() { http.HandleFunc("/", myHandler) server := http.Server{ Addr: ":8080", ConnContext: SaveConnInContext, } server.ListenAndServe() } func myHandler(w http.ResponseWriter, r *http.Request) { conn := GetConn(r) ... }</code>
Für Server, die TCP-Ports überwachen, ist net.Conn.RemoteAddr().String( ) ist für jede Verbindung eindeutig. Daher kann es als Schlüssel für eine globale Verbindungskarte verwendet werden:
<code class="go">package main import ( "net/http" "net" "fmt" "log" ) var conns = make(map[string]net.Conn) func ConnStateEvent(conn net.Conn, event http.ConnState) { if event == http.StateActive { conns[conn.RemoteAddr().String()] = conn } else if event == http.StateHijacked || event == http.StateClosed { delete(conns, conn.RemoteAddr().String()) } } func GetConn(r *http.Request) (net.Conn) { return conns[r.RemoteAddr] } func main() { http.HandleFunc("/", myHandler) server := http.Server{ Addr: ":8080", ConnState: ConnStateEvent, } server.ListenAndServe() } func myHandler(w http.ResponseWriter, r *http.Request) { conn := GetConn(r) ... }</code>
Für Server, die auf UNIX-Sockets lauschen, net.Conn.RemoteAddr() .String() gibt immer „@“ zurück. Damit es funktioniert, können Sie net.Listener.Accept() überschreiben und damit net.Conn.RemoteAddr().String() überschreiben. Hier ist ein Beispiel:
<code class="go">package main import ( "net/http" "net" "os" "golang.org/x/sys/unix" "fmt" "log" ) func main() { http.HandleFunc("/", myHandler) listenPath := "/var/run/go_server.sock" l, err := NewUnixListener(listenPath) if err != nil { log.Fatal(err) } defer os.Remove(listenPath) server := http.Server{ ConnState: ConnStateEvent, } server.Serve(NewConnSaveListener(l)) } func myHandler(w http.ResponseWriter, r *http.Request) { conn := GetConn(r) if unixConn, isUnix := conn.(*net.UnixConn); isUnix { f, _ := unixConn.File() pcred, _ := unix.GetsockoptUcred(int(f.Fd()), unix.SOL_SOCKET, unix.SO_PEERCRED) f.Close() log.Printf("Remote UID: %d", pcred.Uid) } } var conns = make(map[string]net.Conn) type connSaveListener struct { net.Listener } func NewConnSaveListener(wrap net.Listener) (net.Listener) { return connSaveListener{wrap} } func (self connSaveListener) Accept() (net.Conn, error) { conn, err := self.Listener.Accept() ptrStr := fmt.Sprintf("%d", &conn) conns[ptrStr] = conn return remoteAddrPtrConn{conn, ptrStr}, err } func GetConn(r *http.Request) (net.Conn) { return conns[r.RemoteAddr] } func ConnStateEvent(conn net.Conn, event http.ConnState) { if event == http.StateHijacked || event == http.StateClosed { delete(conns, conn.RemoteAddr().String()) } } type remoteAddrPtrConn struct { net.Conn ptrStr string } func (self remoteAddrPtrConn) RemoteAddr() (net.Addr) { return remoteAddrPtr{self.ptrStr} } type remoteAddrPtr struct { ptrStr string } func (remoteAddrPtr) Network() (string) { return "" } func (self remoteAddrPtr) String() (string) { return self.ptrStr } func NewUnixListener(path string) (net.Listener, error) { if err := unix.Unlink(path); err != nil & os.IsNotExist(err) { return nil, err } mask := unix.Umask(0777) defer unix.Umask(mask) l, err := net.Listen("unix", path) if err != nil { return nil, err } if err := os.Chmod(path, 0660); err != nil { l.Close() return nil, err } return l, nil }</code>
Der Zugriff auf den zugrunde liegenden Socket eines http.ResponseWriter kann mit den oben beschriebenen Methoden erreicht werden. Der bevorzugte Ansatz hängt von den spezifischen Anforderungen und der verwendeten Go-Version ab.
Das obige ist der detaillierte Inhalt vonWie greife ich auf den zugrunde liegenden Socket einer Netz-/http-Antwort zu?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!